diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d496fe7eeb0d8..190de66932cc6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -558,6 +558,8 @@ Improvements to Clang's diagnostics - Clang now diagnoses ``= delete("reason")`` extension warnings only in pedantic mode rather than on by default. (#GH109311). +- Clang now diagnoses missing return value in functions containing ``if consteval`` (#GH116485). + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index f678ac6f2ff36..7a6bd8b6f8d07 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -3177,11 +3177,14 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { if (!I->isConsteval()) KnownVal = tryEvaluateBool(I->getCond()); - // Add the successors. If we know that specific branches are + // Add the successors. If we know that specific branches are // unreachable, inform addSuccessor() of that knowledge. addSuccessor(Block, ThenBlock, /* IsReachable = */ !KnownVal.isFalse()); addSuccessor(Block, ElseBlock, /* IsReachable = */ !KnownVal.isTrue()); + if (I->isConsteval()) + return Block; + // Add the condition as the last statement in the new block. This may // create new blocks as the condition may contain control-flow. Any newly // created blocks will be pointed to be "Block". diff --git a/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp b/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp index 25d1f8df7f716..19e7d4976428a 100644 --- a/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp +++ b/clang/test/SemaCXX/constexpr-return-non-void-cxx2b.cpp @@ -1,7 +1,36 @@ -// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -Wimplicit-fallthrough -verify %s constexpr int f() { } // expected-warning {{non-void function does not return a value}} static_assert(__is_same(decltype([] constexpr -> int { }( )), int)); // expected-warning {{non-void lambda does not return a value}} consteval int g() { } // expected-warning {{non-void function does not return a value}} static_assert(__is_same(decltype([] consteval -> int { }( )), int)); // expected-warning {{non-void lambda does not return a value}} + +namespace GH116485 { +int h() { + if consteval { } +} // expected-warning {{non-void function does not return a value}} + +void i(int x) { + if consteval { + } + switch (x) { + case 1: + i(1); + case 2: // expected-warning {{unannotated fall-through between switch labels}} \ + // expected-note {{insert 'break;' to avoid fall-through}} + break; + } +} + +constexpr bool j() { + if !consteval { return true; } +} // expected-warning {{non-void function does not return a value in all control paths}} \ + // expected-note {{control reached end of constexpr function}} + +bool k = j(); +constinit bool l = j(); // expected-error {{variable does not have a constant initializer}} \ + // expected-note {{required by 'constinit' specifier here}} \ + // expected-note {{in call to 'j()'}} + +}