Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -384,6 +384,9 @@ (`#57081: `_) - Clang no longer emits inappropriate notes about the loss of ``__unaligned`` qualifier on overload resolution, when the actual reason for the failure is loss of other qualifiers. +- Clang now diagnoses wider cases of tautological use of consteval if or std::is_constant_evaluated. + (`#43760: `_) + (`#51567: `_) Bug Fixes in This Version ------------------------- Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -408,10 +408,6 @@ def note_unimplemented_constexpr_lambda_feature_ast : Note< "unimplemented constexpr lambda feature: %0 (coming soon!)">; -def warn_is_constant_evaluated_always_true_constexpr : Warning< - "'%0' will always evaluate to 'true' in a manifestly constant-evaluated expression">, - InGroup>; - // inline asm related. let CategoryName = "Inline Assembly Issue" in { def err_asm_invalid_escape : Error< Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1544,7 +1544,7 @@ "expression evaluates to '%0 %1 %2'">; def warn_consteval_if_always_true : Warning< - "consteval if is always true in an %select{unevaluated|immediate}0 context">, + "consteval if is always %select{true|false}0 in this context">, InGroup>; def ext_inline_variable : ExtWarn< @@ -8818,6 +8818,9 @@ def warn_side_effects_typeid : Warning< "expression with side effects will be evaluated despite being used as an " "operand to 'typeid'">, InGroup; +def warn_is_constant_evaluated_tauto_constexpr : Warning< + "'%select{std::is_constant_evaluated|__builtin_is_constant_evaluated}0' will always evaluate to %select{false|true}1 in this context">, + InGroup>; def warn_unused_result : Warning< "ignoring return value of function declared with %0 attribute">, InGroup; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -1335,6 +1335,9 @@ bool InDiscardedStatement; bool InImmediateFunctionContext; bool InImmediateEscalatingFunctionContext; + // The immediate occurances of consteval if or std::is_constant_evaluated() + // are tautologically false + bool IsRuntimeEvaluated; bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false; @@ -1364,7 +1367,8 @@ NumCleanupObjects(NumCleanupObjects), NumTypos(0), ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext), InDiscardedStatement(false), InImmediateFunctionContext(false), - InImmediateEscalatingFunctionContext(false) {} + InImmediateEscalatingFunctionContext(false), + IsRuntimeEvaluated(false) {} bool isUnevaluated() const { return Context == ExpressionEvaluationContext::Unevaluated || Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -12093,21 +12093,6 @@ } case Builtin::BI__builtin_is_constant_evaluated: { - const auto *Callee = Info.CurrentCall->getCallee(); - if (Info.InConstantContext && !Info.CheckingPotentialConstantExpression && - (Info.CallStackDepth == 1 || - (Info.CallStackDepth == 2 && Callee->isInStdNamespace() && - Callee->getIdentifier() && - Callee->getIdentifier()->isStr("is_constant_evaluated")))) { - // FIXME: Find a better way to avoid duplicated diagnostics. - if (Info.EvalStatus.Diag) - Info.report((Info.CallStackDepth == 1) ? E->getExprLoc() - : Info.CurrentCall->CallLoc, - diag::warn_is_constant_evaluated_always_true_constexpr) - << (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated" - : "std::is_constant_evaluated"); - } - return Success(Info.InConstantContext, E); } Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -2384,6 +2384,15 @@ return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo); } +/// Determine whether the given declaration is a global variable or +/// static data member. +static bool isNonlocalVariable(const Decl *D) { + if (const VarDecl *Var = dyn_cast_or_null(D)) + return Var->hasGlobalStorage(); + + return false; +} + Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) { // RAII type used to track whether we're inside an initializer. @@ -2416,6 +2425,37 @@ ThisDecl = nullptr; } }; + struct EnterInitializerExpressionEvaluationContext { + Sema &S; + bool Entered; + + EnterInitializerExpressionEvaluationContext(Sema &S, Declarator &D, + Decl *ThisDecl) + : S(S), Entered(false) { + if (ThisDecl && S.getLangOpts().CPlusPlus && !ThisDecl->isInvalidDecl()) { + Entered = true; + bool RuntimeEvaluated = S.ExprEvalContexts.back().IsRuntimeEvaluated; + Sema::ExpressionEvaluationContext NewEEC = + S.ExprEvalContexts.back().Context; + if ((D.getDeclSpec().getTypeQualifiers() == DeclSpec::TQ_const || + isNonlocalVariable(ThisDecl)) && + S.ExprEvalContexts.back().IsRuntimeEvaluated) { + NewEEC = Sema::ExpressionEvaluationContext::PotentiallyEvaluated; + RuntimeEvaluated = false; + } + if (D.getDeclSpec().hasConstexprSpecifier()) { + NewEEC = Sema::ExpressionEvaluationContext::ConstantEvaluated; + RuntimeEvaluated = false; + } + S.PushExpressionEvaluationContext(NewEEC, ThisDecl); + S.ExprEvalContexts.back().IsRuntimeEvaluated = RuntimeEvaluated; + } + } + ~EnterInitializerExpressionEvaluationContext() { + if (Entered) + S.PopExpressionEvaluationContext(); + } + }; enum class InitKind { Uninitialized, Equal, CXXDirect, CXXBraced }; InitKind TheInitKind; @@ -2514,6 +2554,7 @@ << getLangOpts().CPlusPlus20; } else { InitializerScopeRAII InitScope(*this, D, ThisDecl); + EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl); if (Tok.is(tok::code_completion)) { cutOffParsing(); @@ -2561,6 +2602,7 @@ ExprVector Exprs; InitializerScopeRAII InitScope(*this, D, ThisDecl); + EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl); auto ThisVarDecl = dyn_cast_or_null(ThisDecl); auto RunSignatureHelp = [&]() { @@ -2611,6 +2653,7 @@ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); InitializerScopeRAII InitScope(*this, D, ThisDecl); + EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl); PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl); ExprResult Init(ParseBraceInitializer()); Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -3209,9 +3209,14 @@ assert(Tok.isOneOf(tok::equal, tok::l_brace) && "Data member initializer not starting with '=' or '{'"); + bool IsConstexpr = false; + if (const auto *VD = dyn_cast_if_present(D)) + IsConstexpr = VD->isConstexpr(); + EnterExpressionEvaluationContext Context( Actions, - isa_and_present(D) + IsConstexpr ? Sema::ExpressionEvaluationContext::ConstantEvaluated + : isa_and_present(D) ? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed : Sema::ExpressionEvaluationContext::PotentiallyEvaluated, D); Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -1510,6 +1510,11 @@ SourceLocation RParen; std::optional ConstexprCondition; if (!IsConsteval) { + EnterExpressionEvaluationContext Consteval( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated, + /*LambdaContextDecl=*/nullptr, + Sema::ExpressionEvaluationContextRecord::EK_Other, + /*ShouldEnter=*/IsConstexpr); if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, IsConstexpr ? Sema::ConditionKind::ConstexprIf @@ -1557,11 +1562,16 @@ if (NotLocation.isInvalid() && IsConsteval) { Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext; ShouldEnter = true; + } else if (NotLocation.isValid() && IsConsteval) { + Context = Actions.ExprEvalContexts.back().Context; + ShouldEnter = true; } EnterExpressionEvaluationContext PotentiallyDiscarded( Actions, Context, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter); + if (NotLocation.isValid() && IsConsteval) + Actions.ExprEvalContexts.back().IsRuntimeEvaluated = true; ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc); } @@ -1602,11 +1612,16 @@ if (NotLocation.isValid() && IsConsteval) { Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext; ShouldEnter = true; + } else if (NotLocation.isInvalid() && IsConsteval) { + Context = Actions.ExprEvalContexts.back().Context; + ShouldEnter = true; } EnterExpressionEvaluationContext PotentiallyDiscarded( Actions, Context, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter); + if (NotLocation.isInvalid() && IsConsteval) + Actions.ExprEvalContexts.back().IsRuntimeEvaluated = true; ElseStmt = ParseStatement(); if (ElseStmt.isUsable()) Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -15238,7 +15238,7 @@ // Do not push if it is a lambda because one is already pushed when building // the lambda in ActOnStartOfLambdaDefinition(). - if (!isLambdaCallOperator(FD)) + if (!isLambdaCallOperator(FD)) { // [expr.const]/p14.1 // An expression or conversion is in an immediate function context if it is // potentially evaluated and either: its innermost enclosing non-block scope @@ -15246,6 +15246,9 @@ PushExpressionEvaluationContext( FD->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext : ExprEvalContexts.back().Context); + if (!FD->isConsteval() && !FD->isConstexpr()) + ExprEvalContexts.back().IsRuntimeEvaluated = true; + } // Each ExpressionEvaluationContextRecord also keeps track of whether the // context is nested in an immediate function context, so smaller contexts Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -17959,15 +17959,6 @@ Diag(D->getLocation(), diag::err_illegal_initializer); } -/// Determine whether the given declaration is a global variable or -/// static data member. -static bool isNonlocalVariable(const Decl *D) { - if (const VarDecl *Var = dyn_cast_or_null(D)) - return Var->hasGlobalStorage(); - - return false; -} - /// Invoked when we are about to parse an initializer for the declaration /// 'Dcl'. /// @@ -17990,9 +17981,6 @@ // If we are parsing the initializer for a static data member, push a // new expression evaluation context that is associated with this static // data member. - if (isNonlocalVariable(D)) - PushExpressionEvaluationContext( - ExpressionEvaluationContext::PotentiallyEvaluated, D); } /// Invoked after we are finished parsing an initializer for the declaration D. @@ -18001,9 +17989,6 @@ if (!D || D->isInvalidDecl()) return; - if (isNonlocalVariable(D)) - PopExpressionEvaluationContext(); - if (S && D->isOutOfLine()) ExitDeclaratorContext(S); } Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -7035,6 +7035,30 @@ << FixItHint::CreateInsertion(DRE->getLocation(), "std::"); } +// Diagnose uses of std::is_constant_evaluated or +// __builtin_is_constant_evaluated in contexts where the result is known at +// compile time. +static void DiagnoseTautologicalIsConstantEvaluated(Sema &S, CallExpr *CE) { + if (S.inTemplateInstantiation()) + return; + if (const FunctionDecl *FD = CE->getDirectCallee()) { + bool IsBuiltin = + FD->getBuiltinID() == Builtin::BI__builtin_is_constant_evaluated; + + if ((FD->isInStdNamespace() && + FD->getNameAsString() == "is_constant_evaluated") || + IsBuiltin) { + bool AlwaysTrue = S.ExprEvalContexts.back().isConstantEvaluated() || + S.ExprEvalContexts.back().isUnevaluated(); + bool AlwaysFalse = S.ExprEvalContexts.back().IsRuntimeEvaluated; + if (AlwaysTrue || AlwaysFalse) + S.Diag(CE->getBeginLoc(), + diag::warn_is_constant_evaluated_tauto_constexpr) + << IsBuiltin << AlwaysTrue; + } + } +} + ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig) { @@ -7061,8 +7085,10 @@ ExecConfig); if (LangOpts.CPlusPlus) { CallExpr *CE = dyn_cast(Call.get()); - if (CE) + if (CE) { DiagnosedUnqualifiedCallsToStdFunctions(*this, CE); + DiagnoseTautologicalIsConstantEvaluated(*this, CE); + } } return Call; } Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -1420,6 +1420,8 @@ PushExpressionEvaluationContext( LSI->CallOperator->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext + : isConstantEvaluated() + ? ExpressionEvaluationContext::ConstantEvaluated : ExpressionEvaluationContext::PotentiallyEvaluated); ExprEvalContexts.back().InImmediateFunctionContext = LSI->CallOperator->isConsteval(); Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -933,16 +933,15 @@ } if (ConstevalOrNegatedConsteval) { - bool Immediate = ExprEvalContexts.back().Context == - ExpressionEvaluationContext::ImmediateFunctionContext; - if (CurContext->isFunctionOrMethod()) { - const auto *FD = - dyn_cast(Decl::castFromDeclContext(CurContext)); - if (FD && FD->isImmediateFunction()) - Immediate = true; - } - if (isUnevaluatedContext() || Immediate) - Diags.Report(IfLoc, diag::warn_consteval_if_always_true) << Immediate; + bool AlwaysTrue = ExprEvalContexts.back().isConstantEvaluated() || + ExprEvalContexts.back().isUnevaluated(); + bool AlwaysFalse = ExprEvalContexts.back().IsRuntimeEvaluated; + if (AlwaysTrue) + Diags.Report(IfLoc, diag::warn_consteval_if_always_true) + << (StatementKind == IfStatementKind::ConstevalNegated); + else if (AlwaysFalse) + Diags.Report(IfLoc, diag::warn_consteval_if_always_true) + << (StatementKind == IfStatementKind::ConstevalNonNegated); } return BuildIfStmt(IfLoc, StatementKind, LParenLoc, InitStmt, Cond, RParenLoc, Index: clang/test/AST/Interp/builtins.cpp =================================================================== --- clang/test/AST/Interp/builtins.cpp +++ clang/test/AST/Interp/builtins.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -S -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -Wno-constant-evaluated -verify +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -Wno-constant-evaluated -S -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated // RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated %s -S -emit-llvm -o - | FileCheck %s Index: clang/test/AST/Interp/if.cpp =================================================================== --- clang/test/AST/Interp/if.cpp +++ clang/test/AST/Interp/if.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify -// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter -Wno-redundant-consteval-if %s -verify +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -Wno-redundant-consteval-if %s -verify=ref // expected-no-diagnostics // ref-no-diagnostics Index: clang/test/AST/Interp/literals.cpp =================================================================== --- clang/test/AST/Interp/literals.cpp +++ clang/test/AST/Interp/literals.cpp @@ -169,15 +169,11 @@ #if __cplusplus >= 202002L /// FIXME: The following code should be accepted. consteval int foo(int n) { // ref-error {{consteval function never produces a constant expression}} - return sizeof(int[n]); // ref-note 3{{not valid in a constant expression}} \ - // expected-note {{not valid in a constant expression}} + return sizeof(int[n]); // ref-note 2 {{not valid in a constant expression}} } - constinit int var = foo(5); // ref-error {{not a constant expression}} \ - // ref-note 2{{in call to}} \ + constinit int var = foo(5); // ref-note {{in call to}} \ // ref-error {{does not have a constant initializer}} \ // ref-note {{required by 'constinit' specifier}} \ - // expected-error {{is not a constant expression}} \ - // expected-note {{in call to}} \ // expected-error {{does not have a constant initializer}} \ // expected-note {{required by 'constinit' specifier}} \ Index: clang/test/CXX/expr/expr.const/p2-0x.cpp =================================================================== --- clang/test/CXX/expr/expr.const/p2-0x.cpp +++ clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -244,8 +244,8 @@ constexpr int n13 = n5 + n5; // expected-error {{constant expression}} expected-note {{value -4294967296 is outside the range of }} constexpr int n14 = n3 - n5; // expected-error {{constant expression}} expected-note {{value 4294967295 is outside the range of }} constexpr int n15 = n5 * n5; // expected-error {{constant expression}} expected-note {{value 4611686018427387904 is outside the range of }} - constexpr signed char c1 = 100 * 2; // ok expected-warning{{changes value}} - constexpr signed char c2 = '\x64' * '\2'; // also ok expected-warning{{changes value}} + constexpr signed char c1 = 100 * 2; // ok + constexpr signed char c2 = '\x64' * '\2'; // also ok constexpr long long ll1 = 0x7fffffffffffffff; // ok constexpr long long ll2 = ll1 + 1; // expected-error {{constant}} expected-note {{ 9223372036854775808 }} constexpr long long ll3 = -ll1 - 1; // ok Index: clang/test/CXX/expr/expr.const/p6-2a.cpp =================================================================== --- clang/test/CXX/expr/expr.const/p6-2a.cpp +++ clang/test/CXX/expr/expr.const/p6-2a.cpp @@ -43,12 +43,11 @@ constexpr Temporary t = {3}; // expected-error {{must have constant destruction}} expected-note {{created here}} expected-note {{in call}} namespace P1073R3 { -consteval int f() { return 42; } // expected-note 2 {{declared here}} +consteval int f() { return 42; } // expected-note {{declared here}} consteval auto g() { return f; } consteval int h(int (*p)() = g()) { return p(); } constexpr int r = h(); -constexpr auto e = g(); // expected-error {{call to consteval function 'P1073R3::g' is not a constant expression}} \ - expected-error {{constexpr variable 'e' must be initialized by a constant expression}} \ - expected-note 2 {{pointer to a consteval declaration is not a constant expression}} +constexpr auto e = g(); // expected-error {{constexpr variable 'e' must be initialized by a constant expression}} \ + expected-note {{pointer to a consteval declaration is not a constant expression}} static_assert(r == 42); } // namespace P1073R3 Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp =================================================================== --- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp +++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp @@ -16,4 +16,5 @@ #if __cplusplus < 201703L // expected-error@-2 {{constexpr variable cannot have non-literal type}} // expected-note@-3 {{lambda closure types are non-literal types before C++17}} +// expected-error@-4 {{a lambda expression may not appear inside of a constant expression}} #endif Index: clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p4.cpp =================================================================== --- clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p4.cpp +++ clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p4.cpp @@ -8,14 +8,14 @@ } else (void)0; // expected-error {{expected { after else}} static_assert([] { - if consteval { + if consteval { // expected-warning {{consteval if is always true}} return 0; } return 1; }() == 0); static_assert([] { - if consteval { + if consteval { // expected-warning {{consteval if is always true}} return 0; } else { return 1; @@ -23,7 +23,7 @@ }() == 0); static_assert([] { - if !consteval { + if !consteval { // expected-warning {{consteval if is always false}} return 0; } else { return 1; @@ -31,14 +31,15 @@ }() == 1); static_assert([] { - if not consteval { + if not consteval { // expected-warning {{consteval if is always false}} return 0; } return 1; }() == 1); if consteval [[likely]] { // expected-warning {{attribute 'likely' has no effect when annotating an 'if consteval' statement}}\ - // expected-note 2{{annotating the 'if consteval' statement here}} + // expected-note 2{{annotating the 'if consteval' statement here}} \ + // expected-warning {{consteval if is always false}} } @@ -49,7 +50,8 @@ } void test_consteval_jumps() { - if consteval { // expected-note 4{{jump enters controlled statement of consteval if}} + if consteval { // expected-warning {{consteval if is always false}} \ + // expected-note 4{{jump enters controlled statement of consteval if}} goto a; goto b; // expected-error {{cannot jump from this goto statement to its label}} a:; @@ -65,14 +67,16 @@ void test_consteval_switch() { int x = 42; switch (x) { - if consteval { // expected-note 2{{jump enters controlled statement of consteval if}} + if consteval { // expected-warning {{consteval if is always false}} \ + // expected-note 2{{jump enters controlled statement of consteval if}} case 1:; // expected-error {{cannot jump from switch statement to this case label}} default:; // expected-error {{cannot jump from switch statement to this case label}} } else { } } switch (x) { - if consteval { // expected-note 2{{jump enters controlled statement of consteval if}} + if consteval { // expected-warning {{consteval if is always false}} \ + // expected-note 2{{jump enters controlled statement of consteval if}} } else { case 2:; // expected-error {{cannot jump from switch statement to this case label}} default:; // expected-error {{cannot jump from switch statement to this case label}} @@ -99,32 +103,32 @@ } consteval void warn_in_consteval() { - if consteval { // expected-warning {{consteval if is always true in an immediate context}} - if consteval {} // expected-warning {{consteval if is always true in an immediate context}} + if consteval { // expected-warning {{consteval if is always true in this context}} + if consteval {} // expected-warning {{consteval if is always true in this context}} } } constexpr void warn_in_consteval2() { if consteval { - if consteval {} // expected-warning {{consteval if is always true in an immediate context}} + if consteval {} // expected-warning {{consteval if is always true in this context}} } } auto y = []() consteval { - if consteval { // expected-warning {{consteval if is always true in an immediate context}} - if consteval {} // expected-warning {{consteval if is always true in an immediate context}} + if consteval { // expected-warning {{consteval if is always true in this context}} + if consteval {} // expected-warning {{consteval if is always true in this context}} } }; namespace test_transform { int f(auto n) { - if consteval { + if consteval { // expected-warning {{consteval if is always false}} n.foo; //expected-error {{no member named}} } else { } - if !consteval { + if !consteval { // expected-warning {{consteval if is always true}} n.foo; //expected-error {{no member named}} } else { Index: clang/test/Parser/pragma-fenv_access.c =================================================================== --- clang/test/Parser/pragma-fenv_access.c +++ clang/test/Parser/pragma-fenv_access.c @@ -33,7 +33,7 @@ CONST float fnot_too_big = not_too_big; CONST int too_big = 0x7ffffff0; #if defined(CPP) -//expected-warning@+2{{implicit conversion}} +// FIXME: should diagnose the narrowing happening below #endif CONST float fbig = too_big; // inexact #if !defined(CPP) Index: clang/test/SemaCXX/constant-expression-cxx11.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx11.cpp +++ clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1961,7 +1961,7 @@ namespace Lifetime { void f() { - constexpr int &n = n; // expected-error {{constant expression}} expected-note {{use of reference outside its lifetime}} expected-warning {{not yet bound to a value}} + constexpr int &n = n; // expected-error {{constant expression}} expected-note {{use of reference outside its lifetime}} constexpr int m = m; // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}} } Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ clang/test/SemaCXX/cxx2a-consteval.cpp @@ -713,7 +713,7 @@ struct test { consteval int operator[](int i) const { return {}; } consteval const derp * operator->() const { return &d; } - consteval int f() const { return 12; } // expected-note 2{{declared here}} + consteval int f() const { return 12; } // expected-note {{declared here}} }; constexpr test a; @@ -726,8 +726,7 @@ constexpr int t = a[1]; constexpr int u = a.operator->()->b; constexpr int v = a->b; -// FIXME: I believe this case should work, but we currently reject. -constexpr int w = (a.*&test::f)(); // expected-error {{cannot take address of consteval function 'f' outside of an immediate invocation}} +constexpr int w = (a.*&test::f)(); constexpr int x = a.f(); // Show that we reject when not in an immediate context. @@ -1073,18 +1072,17 @@ consteval const char* make_name(const char* name) { return name;} consteval const char* pad(int P) { return "thestring"; } -int bad = 10; // expected-note 6{{declared here}} +int bad = 10; // expected-note 5{{declared here}} tester glob1(make_name("glob1")); tester glob2(make_name("glob2")); constexpr tester cglob(make_name("cglob")); -tester paddedglob(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \ +tester paddedglob(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \ // expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}} constexpr tester glob3 = { make_name("glob3") }; -constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \ - // expected-error {{constexpr variable 'glob4' must be initialized by a constant expression}} \ - // expected-note 2{{read of non-const variable 'bad' is not allowed in a constant expression}} +constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{constexpr variable 'glob4' must be initialized by a constant expression}} \ + // expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}} auto V = make_name(pad(3)); auto V1 = make_name(pad(bad)); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \ @@ -1094,12 +1092,12 @@ void foo() { static tester loc1(make_name("loc1")); static constexpr tester loc2(make_name("loc2")); - static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \ + static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \ // expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}} } void bar() { - static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \ + static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \ // expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}} } } Index: clang/test/SemaCXX/cxx2b-consteval-if.cpp =================================================================== --- clang/test/SemaCXX/cxx2b-consteval-if.cpp +++ clang/test/SemaCXX/cxx2b-consteval-if.cpp @@ -18,7 +18,7 @@ constexpr auto i() { if consteval { - if consteval { // expected-warning {{consteval if is always true in an immediate context}} + if consteval { // expected-warning {{consteval if is always true in this context}} return 1; } return 2; Index: clang/test/SemaCXX/ext-int.cpp =================================================================== --- clang/test/SemaCXX/ext-int.cpp +++ clang/test/SemaCXX/ext-int.cpp @@ -25,7 +25,7 @@ unsigned _BitInt(1) l; signed _BitInt(1) m; // expected-error{{signed _BitInt must have a bit size of at least 2}} - constexpr _BitInt(6) n = 33; // expected-warning{{implicit conversion from 'int' to 'const _BitInt(6)' changes value from 33 to -31}} + constexpr _BitInt(6) n = 33; constexpr _BitInt(7) o = 33; // Check imposed max size. Index: clang/test/SemaCXX/vartemplate-lambda.cpp =================================================================== --- clang/test/SemaCXX/vartemplate-lambda.cpp +++ clang/test/SemaCXX/vartemplate-lambda.cpp @@ -12,7 +12,9 @@ struct S { template - static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't' must be initialized by a constant expression}} expected-note{{cannot be used in a constant expression}} + static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't' must be initialized by a constant expression}} \ + // expected-note{{cannot be used in a constant expression}} \ + // expected-error{{a lambda expression may not appear inside of a constant expression}} }; template Index: clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp =================================================================== --- clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp +++ clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp @@ -7,35 +7,35 @@ } // namespace std constexpr int fn1() { - if constexpr (std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}} + if constexpr (std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to true in this context}} return 0; else return 1; } constexpr int fn2() { - if constexpr (!std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}} + if constexpr (!std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to true in this context}} return 0; else return 1; } constexpr int fn3() { - if constexpr (std::is_constant_evaluated() == false) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}} + if constexpr (std::is_constant_evaluated() == false) // expected-warning {{'std::is_constant_evaluated' will always evaluate to true in this context}} return 0; else return 1; } constexpr int fn4() { - if constexpr (__builtin_is_constant_evaluated() == true) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}} + if constexpr (__builtin_is_constant_evaluated() == true) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to true in this context}} return 0; else return 1; } constexpr int fn5() { - if constexpr (__builtin_is_constant_evaluated()) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}} + if constexpr (__builtin_is_constant_evaluated()) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to true in this context}} return 0; else return 1; Index: clang/test/SemaCXX/warn-tautological-meta-constant.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/warn-tautological-meta-constant.cpp @@ -0,0 +1,170 @@ +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify %s + +namespace std { +constexpr inline bool + is_constant_evaluated() noexcept { + if consteval { return true; } else { return false; } + } +} // namespace std + +namespace P1938 { + constexpr int f1() { + if constexpr (!std::is_constant_evaluated() && sizeof(int) == 4) { // expected-warning {{always evaluate to true}} + return 0; + } + if (std::is_constant_evaluated()) { + return 42; + } else { + if constexpr (std::is_constant_evaluated()) { // expected-warning {{always evaluate to true}} + return 0; + } + } + return 7; +} + + +consteval int f2() { + if (std::is_constant_evaluated() && f1()) { // expected-warning {{always evaluate to true}} + return 42; + } + return 7; +} + + +int f3() { + if (std::is_constant_evaluated() && f1()) { // expected-warning {{always evaluate to false}} + return 42; + } + return 7; +} +} + +void non_qual() { + int ff = std::is_constant_evaluated(); // expected-warning {{always evaluate to false}} + const int aa = std::is_constant_evaluated(); + constexpr int tt = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + static int bb = std::is_constant_evaluated(); + constexpr int cc = [](){ + if consteval {return 8;} // expected-warning {{always true}} + }(); + auto lamda = []() { + if consteval {return 8;} + else {return 4;} + }; + auto lamda_const = []() consteval { + if consteval {return 8;} // expected-warning {{always true}} + else {return 4;} + }; + if consteval { // expected-warning {{always false}} + int b = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + } +} + +constexpr void in_constexpr() { + int aa = std::is_constant_evaluated(); + constexpr int bb = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + const int cc = std::is_constant_evaluated(); + if consteval { + int dd = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + constexpr int ee = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + const int ff = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + } else { + int dd = std::is_constant_evaluated(); // expected-warning {{always evaluate to false}} + constexpr int ee = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + const int ff = std::is_constant_evaluated(); + const int qq = std::is_constant_evaluated() ? dd : 3; + } + + if consteval { + if consteval {} // expected-warning {{always true}} + if !consteval {} // expected-warning {{always false}} + } else { + if consteval {} // expected-warning {{always false}} + if !consteval {} // expected-warning {{always true}} + } + if !consteval { + if consteval {} // expected-warning {{always false}} + if !consteval {} // expected-warning {{always true}} + } else { + if consteval {} // expected-warning {{always true}} + if !consteval {} // expected-warning {{always false}} + } +} + +consteval void in_consteval() { + int aa = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + constexpr int bb = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + const int cc = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + auto lambda = []() { + int a(std::is_constant_evaluated()); // expected-warning {{always evaluate to true}} + constexpr int b = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + const int c = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + }; + if !consteval {} // expected-warning {{always false}} +} + +static_assert(std::is_constant_evaluated()); // expected-warning {{always evaluate to true}} +static_assert(__builtin_is_constant_evaluated()); // expected-warning {{always evaluate to true}} + +template +void templ() { + if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}} + constexpr bool c = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + if consteval {} // expected-warning {{always false}} +} + +template <> void templ() { // expected-warning {{always evaluate to true}} + if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}} + constexpr bool c = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + if consteval {} // expected-warning {{always false}} + templ(); +} + +static_assert([] { + if consteval { // expected-warning {{always true}} + return 0; + } else { + return 1; + } + }() == 0); +constexpr bool b = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}} +constexpr bool c = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} +constinit bool d = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} +int p = __builtin_is_constant_evaluated(); +const int q = __builtin_is_constant_evaluated(); + +template // expected-warning {{always evaluate to true}} +void vvv() { + return; +} + +template<> void vvv() {} +template<> void vvv() {} + +template concept C = __builtin_is_constant_evaluated();// expected-warning {{always evaluate to true}} + +struct Foo { + static constexpr bool ce = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + const static bool nonce = std::is_constant_evaluated(); + bool b = std::is_constant_evaluated(); + + Foo() { + if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}} + bool aa = std::is_constant_evaluated(); // expected-warning {{always evaluate to false}} + static bool bb = std::is_constant_evaluated(); + constexpr bool cc = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + if consteval {} // expected-warning {{always false}} + } + constexpr Foo(int) { + if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}} + bool aa = std::is_constant_evaluated(); + static bool bb = std::is_constant_evaluated(); + constexpr bool cc = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + } + consteval Foo(int *) { + if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}} + bool aa = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + static bool bb = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + constexpr bool cc = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}} + } +}; Index: clang/test/SemaTemplate/concepts.cpp =================================================================== --- clang/test/SemaTemplate/concepts.cpp +++ clang/test/SemaTemplate/concepts.cpp @@ -135,21 +135,21 @@ namespace BuiltinIsConstantEvaluated { // Check that we do all satisfaction and diagnostic checks in a constant context. - template concept C = __builtin_is_constant_evaluated(); // expected-warning {{always}} + template concept C = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}} static_assert(C); - template concept D = __builtin_is_constant_evaluated() == true; // expected-warning {{always}} + template concept D = __builtin_is_constant_evaluated() == true; // expected-warning {{always evaluate to true}} static_assert(D); - template concept E = __builtin_is_constant_evaluated() == true && // expected-warning {{always}} + template concept E = __builtin_is_constant_evaluated() == true && // expected-warning {{always evaluate to true}} false; // expected-note {{'false' evaluated to false}} static_assert(E); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'E'}} - template concept F = __builtin_is_constant_evaluated() == false; // expected-warning {{always}} + template concept F = __builtin_is_constant_evaluated() == false; // expected-warning {{always evaluate to true}} // expected-note@-1 {{'__builtin_is_constant_evaluated() == false' (1 == 0)}} static_assert(F); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'F'}} - template concept G = __builtin_is_constant_evaluated() && // expected-warning {{always}} + template concept G = __builtin_is_constant_evaluated() && // expected-warning {{always evaluate to true}} false; // expected-note {{'false' evaluated to false}} static_assert(G); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'G'}} } Index: clang/unittests/Support/TimeProfilerTest.cpp =================================================================== --- clang/unittests/Support/TimeProfilerTest.cpp +++ clang/unittests/Support/TimeProfilerTest.cpp @@ -188,7 +188,6 @@ | EvaluateAsBooleanCondition () | | EvaluateAsRValue () | EvaluateAsInitializer (slow_value) -| EvaluateAsConstantExpr () | EvaluateAsConstantExpr () | EvaluateAsRValue () | EvaluateAsInitializer (slow_init_list) Index: libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp =================================================================== --- libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp +++ libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp @@ -93,12 +93,10 @@ } int main(int, char**) { - if (!std::is_constant_evaluated()) { - test_containers, std::deque>(); - test_containers, std::vector>(); - test_containers, std::deque>(); - test_containers, std::vector>(); - } + test_containers, std::deque>(); + test_containers, std::vector>(); + test_containers, std::deque>(); + test_containers, std::vector>(); types::for_each(types::forward_iterator_list{}, [] { test_join_view(); Index: libcxx/test/std/utilities/meta/meta.const.eval/is_constant_evaluated.verify.cpp =================================================================== --- libcxx/test/std/utilities/meta/meta.const.eval/is_constant_evaluated.verify.cpp +++ libcxx/test/std/utilities/meta/meta.const.eval/is_constant_evaluated.verify.cpp @@ -24,7 +24,7 @@ #else // expected-error-re@+1 {{{{(static_assert|static assertion)}} failed}} static_assert(!std::is_constant_evaluated(), ""); - // expected-warning@-1 0-1 {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}} + // expected-warning@-1 0-1 {{'std::is_constant_evaluated' will always evaluate to}} #endif return 0; }