[clang] 491b281 - [clang][SemaCXX] Diagnose tautological uses of consteval if and is_constant_evaluated

Takuya Shimizu via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 26 17:26:50 PDT 2023


Author: Takuya Shimizu
Date: 2023-09-27T09:26:06+09:00
New Revision: 491b2810fb7fe5f080fa9c4f5945ed0a6909dc92

URL: https://github.com/llvm/llvm-project/commit/491b2810fb7fe5f080fa9c4f5945ed0a6909dc92
DIFF: https://github.com/llvm/llvm-project/commit/491b2810fb7fe5f080fa9c4f5945ed0a6909dc92.diff

LOG: [clang][SemaCXX] Diagnose tautological uses of consteval if and is_constant_evaluated

This patch makes clang diagnose extensive cases of consteval if and is_constant_evaluated usage that are tautologically true or false.
This introduces a new IsRuntimeEvaluated boolean flag to Sema::ExpressionEvaluationContextRecord that means the immediate appearance of if consteval or is_constant_evaluated are tautologically false(e.g. inside if !consteval {} block or non-constexpr-qualified function definition body)
This patch also pushes new expression evaluation context when parsing the condition of if constexpr and initializer of constexpr variables so that Sema can be aware that the use of consteval if and is_consteval are tautologically true in if constexpr condition and constexpr variable initializers.
BEFORE this patch, the warning for is_constant_evaluated was emitted from constant evaluator. This patch moves the warning logic to Sema in order to diagnose tautological use of is_constant_evaluated in the same way as consteval if.

This patch separates initializer evaluation context from InitializerScopeRAII.
This fixes a bug that was happening when user takes address of function address in initializers of non-local variables.

Fixes https://github.com/llvm/llvm-project/issues/43760
Fixes https://github.com/llvm/llvm-project/issues/51567

Reviewed By: cor3ntin, ldionne
Differential Revision: https://reviews.llvm.org/D155064

Added: 
    clang/test/SemaCXX/fixit-tautological-meta-constant.cpp
    clang/test/SemaCXX/warn-tautological-meta-constant.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticASTKinds.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/ExprConstant.cpp
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/lib/Parse/ParseExpr.cpp
    clang/lib/Parse/ParseExprCXX.cpp
    clang/lib/Parse/ParseStmt.cpp
    clang/lib/Sema/SemaChecking.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/SemaLambda.cpp
    clang/lib/Sema/SemaStmt.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/AST/Interp/builtins.cpp
    clang/test/AST/Interp/if.cpp
    clang/test/AST/Interp/literals.cpp
    clang/test/CXX/expr/expr.const/p2-0x.cpp
    clang/test/CXX/expr/expr.const/p6-2a.cpp
    clang/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
    clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p4.cpp
    clang/test/Parser/pragma-fenv_access.c
    clang/test/SemaCXX/constant-conversion.cpp
    clang/test/SemaCXX/constant-expression-cxx11.cpp
    clang/test/SemaCXX/cxx2a-consteval.cpp
    clang/test/SemaCXX/cxx2b-consteval-if.cpp
    clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
    clang/test/SemaCXX/vartemplate-lambda.cpp
    clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp
    clang/test/SemaTemplate/concepts.cpp
    clang/unittests/Support/TimeProfilerTest.cpp
    libcxx/include/__type_traits/is_constant_evaluated.h
    libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp
    libcxx/test/std/utilities/meta/meta.const.eval/is_constant_evaluated.verify.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8a136aae5489a8c..a17efab57bcdfa3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -206,6 +206,12 @@ Improvements to Clang's diagnostics
 - Clang no longer emits irrelevant notes about unsatisfied constraint expressions
   on the left-hand side of ``||`` when the right-hand side constraint is satisfied.
   (`#54678: <https://github.com/llvm/llvm-project/issues/54678>`_).
+- Clang now diagnoses wider cases of tautological use of consteval if or
+  ``std::is_constant_evaluated``. This also suppresses some false positives.
+  (`#43760: <https://github.com/llvm/llvm-project/issues/43760>`_)
+  (`#51567: <https://github.com/llvm/llvm-project/issues/51567>`_)
+- Clang now diagnoses narrowing implicit conversions on variable initializers in immediate
+  function context and on constexpr variable template initializers.
 
 Bug Fixes in This Version
 -------------------------

diff  --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index d2656310e79c9b8..1abb0b89af9f1c1 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -413,10 +413,6 @@ def warn_constexpr_unscoped_enum_out_of_range : Warning<
 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<DiagGroup<"constant-evaluated">>;
-
 // inline asm related.
 let CategoryName = "Inline Assembly Issue" in {
   def err_asm_invalid_escape : Error<

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f4eb02fd9570c2f..3f30681a378e24f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1591,8 +1591,8 @@ def err_static_assert_message_constexpr : Error<
   "the message in a static assertion must be produced by a "
   "constant expression">;
 
-def warn_consteval_if_always_true : Warning<
-  "consteval if is always true in an %select{unevaluated|immediate}0 context">,
+def warn_tautological_consteval_if : Warning<
+  "consteval if is always %select{true|false}0 in this context">,
   InGroup<DiagGroup<"redundant-consteval-if">>;
 
 def ext_inline_variable : ExtWarn<
@@ -8897,6 +8897,9 @@ def warn_side_effects_unevaluated_context : Warning<
 def warn_side_effects_typeid : Warning<
   "expression with side effects will be evaluated despite being used as an "
   "operand to 'typeid'">, InGroup<PotentiallyEvaluatedExpression>;
+def warn_tautological_is_constant_evaluated : Warning<
+  "'%select{std::is_constant_evaluated|__builtin_is_constant_evaluated}0' will always evaluate to %select{false|true}1 in this context">,
+  InGroup<DiagGroup<"constant-evaluated">>;
 def warn_unused_result : Warning<
   "ignoring return value of function declared with %0 attribute">,
   InGroup<UnusedResult>;

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index f599b8b98d031fb..ae3c265f40a2c76 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2003,12 +2003,10 @@ class Parser : public CodeCompletionHandler {
   //===--------------------------------------------------------------------===//
   // C++ if/switch/while/for condition expression.
   struct ForRangeInfo;
-  Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt,
-                                          SourceLocation Loc,
-                                          Sema::ConditionKind CK,
-                                          bool MissingOK,
-                                          ForRangeInfo *FRI = nullptr,
-                                          bool EnterForConditionScope = false);
+  Sema::ConditionResult ParseCXXCondition(
+      StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK,
+      bool MissingOK, ForRangeInfo *FRI = nullptr,
+      bool EnterForConditionScope = false, SourceLocation ConstexprLoc = {});
   DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
                                                       ParsedAttributes &Attrs);
 
@@ -2106,7 +2104,8 @@ class Parser : public CodeCompletionHandler {
                                  Sema::ConditionResult &CondResult,
                                  SourceLocation Loc, Sema::ConditionKind CK,
                                  SourceLocation &LParenLoc,
-                                 SourceLocation &RParenLoc);
+                                 SourceLocation &RParenLoc,
+                                 SourceLocation ConstexprLoc = {});
   StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
   StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
   StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 712db0a3dd895d5..e4366170005a044 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1358,6 +1358,9 @@ class Sema final {
     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;
 
@@ -1387,7 +1390,8 @@ class Sema final {
           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 ||
@@ -1426,6 +1430,10 @@ class Sema final {
   /// A stack of expression evaluation contexts.
   SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
 
+  /// Source location of the start of `constexpr` in constexpr-if
+  /// used for diagnostics
+  SourceLocation ConstexprIfLoc;
+
   // Set of failed immediate invocations to avoid double diagnosing.
   llvm::SmallPtrSet<ConstantExpr *, 4> FailedImmediateInvocations;
 

diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index fea06b97259fe31..310debe327017cd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -12178,22 +12178,6 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
   }
 
   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->getCallRange().getBegin(),
-                    diag::warn_is_constant_evaluated_always_true_constexpr)
-            << (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated"
-                                         : "std::is_constant_evaluated");
-    }
-
     return Success(Info.InConstantContext, E);
   }
 

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 748b9d53c9f5b33..f5b4107cc32c1f0 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2461,6 +2461,15 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
   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<VarDecl>(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.
@@ -2493,6 +2502,36 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
       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) {
+          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;
@@ -2592,6 +2631,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
             << getLangOpts().CPlusPlus20;
     } else {
       InitializerScopeRAII InitScope(*this, D, ThisDecl);
+      EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
 
       if (Tok.is(tok::code_completion)) {
         cutOffParsing();
@@ -2639,6 +2679,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
     ExprVector Exprs;
 
     InitializerScopeRAII InitScope(*this, D, ThisDecl);
+    EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
 
     auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
     auto RunSignatureHelp = [&]() {
@@ -2689,6 +2730,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
     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());

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 5a6b5efbf6c1223..e5a278c598cfb63 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3234,9 +3234,14 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
 
   bool IsFieldInitialization = isa_and_present<FieldDecl>(D);
 
+  bool IsConstexpr = false;
+  if (const auto *VD = dyn_cast_if_present<VarDecl>(D))
+    IsConstexpr = VD->isConstexpr();
+
   EnterExpressionEvaluationContext Context(
       Actions,
-      IsFieldInitialization
+      IsConstexpr ? Sema::ExpressionEvaluationContext::ConstantEvaluated
+      : IsFieldInitialization
           ? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed
           : Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
       D);

diff  --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 74664c34abdbd89..0e69be6bcb3ce4e 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2093,6 +2093,13 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
       };
       if (OpKind == tok::l_paren || !LHS.isInvalid()) {
         if (Tok.isNot(tok::r_paren)) {
+          // FIXME: arguments in consteval functions are constant expression
+          // regardless of the evaluation context of callsite. However, we
+          // cannot know whether the called function is constevasl before the
+          // declaration is resolved.
+          bool IsRuntimeEvaluated =
+              Actions.ExprEvalContexts.back().IsRuntimeEvaluated;
+          Actions.ExprEvalContexts.back().IsRuntimeEvaluated = false;
           if (ParseExpressionList(ArgExprs, [&] {
                 PreferredType.enterFunctionArgument(Tok.getLocation(),
                                                     RunSignatureHelp);
@@ -2109,6 +2116,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
             for (auto &E : ArgExprs)
               Actions.CorrectDelayedTyposInExpr(E);
           }
+          Actions.ExprEvalContexts.back().IsRuntimeEvaluated =
+              IsRuntimeEvaluated;
         }
       }
 

diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 99b4931004546c1..d20d400e3076e9f 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -2041,7 +2041,8 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
 Sema::ConditionResult
 Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
                           Sema::ConditionKind CK, bool MissingOK,
-                          ForRangeInfo *FRI, bool EnterForConditionScope) {
+                          ForRangeInfo *FRI, bool EnterForConditionScope,
+                          SourceLocation ConstexprLoc) {
   // Helper to ensure we always enter a continue/break scope if requested.
   struct ForConditionScopeRAII {
     Scope *S;
@@ -2098,9 +2099,28 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
       *InitStmt = Actions.ActOnNullStmt(SemiLoc);
       return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
     }
+    bool InitStmtIsExprStmt = false;
+    if (InitStmt) {
+      RevertingTentativeParsingAction PA(*this);
+      SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch);
+      InitStmtIsExprStmt = Tok.is(tok::semi);
+    }
 
-    // Parse the expression.
-    ExprResult Expr = ParseExpression(); // expression
+    ExprResult Expr; // expression
+    {
+      EnterExpressionEvaluationContext Consteval(
+          Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+          /*LambdaContextDecl=*/nullptr,
+          Sema::ExpressionEvaluationContextRecord::EK_Other,
+          /*ShouldEnter=*/CK == Sema::ConditionKind::ConstexprIf &&
+              !InitStmtIsExprStmt);
+      SourceLocation OuterConstexprIfLoc = Actions.ConstexprIfLoc;
+      Actions.ConstexprIfLoc = ConstexprLoc;
+
+      // Parse the expression.
+      Expr = ParseExpression(); // expression
+      Actions.ConstexprIfLoc = OuterConstexprIfLoc;
+    }
     if (Expr.isInvalid())
       return Sema::ConditionError();
 
@@ -2188,6 +2208,21 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
   if (CopyInitialization)
     ConsumeToken();
 
+  Sema::ExpressionEvaluationContext NewEEC =
+      Actions.ExprEvalContexts.back().Context;
+  bool RuntimeEvaluated = Actions.ExprEvalContexts.back().IsRuntimeEvaluated;
+  if (DS.getTypeQualifiers() == DeclSpec::TQ_const)
+    RuntimeEvaluated = false;
+
+  if (CK == Sema::ConditionKind::ConstexprIf || DS.hasConstexprSpecifier()) {
+    RuntimeEvaluated = false;
+    NewEEC = Sema::ExpressionEvaluationContext::ConstantEvaluated;
+  }
+  EnterExpressionEvaluationContext Initializer(Actions, NewEEC, DeclOut);
+  Actions.ExprEvalContexts.back().IsRuntimeEvaluated = RuntimeEvaluated;
+  SourceLocation OuterConstexprIfLoc = Actions.ConstexprIfLoc;
+  Actions.ConstexprIfLoc = ConstexprLoc;
+
   ExprResult InitExpr = ExprError();
   if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
     Diag(Tok.getLocation(),
@@ -2214,6 +2249,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
     Actions.ActOnInitializerError(DeclOut);
 
   Actions.FinalizeDeclaration(DeclOut);
+  Actions.ConstexprIfLoc = OuterConstexprIfLoc;
   return Actions.ActOnConditionVariable(DeclOut, Loc, CK);
 }
 

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 2531147c23196ae..75c689f21efa2b1 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1293,18 +1293,17 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
 /// errors in the condition.
 /// Additionally, it will assign the location of the outer-most '(' and ')',
 /// to LParenLoc and RParenLoc, respectively.
-bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
-                                       Sema::ConditionResult &Cond,
-                                       SourceLocation Loc,
-                                       Sema::ConditionKind CK,
-                                       SourceLocation &LParenLoc,
-                                       SourceLocation &RParenLoc) {
+bool Parser::ParseParenExprOrCondition(
+    StmtResult *InitStmt, Sema::ConditionResult &Cond, SourceLocation Loc,
+    Sema::ConditionKind CK, SourceLocation &LParenLoc,
+    SourceLocation &RParenLoc, SourceLocation ConstexprLoc) {
   BalancedDelimiterTracker T(*this, tok::l_paren);
   T.consumeOpen();
   SourceLocation Start = Tok.getLocation();
 
   if (getLangOpts().CPlusPlus) {
-    Cond = ParseCXXCondition(InitStmt, Loc, CK, false);
+    Cond = ParseCXXCondition(InitStmt, Loc, CK, false, nullptr, false,
+                             ConstexprLoc);
   } else {
     ExprResult CondExpr = ParseExpression();
 
@@ -1464,12 +1463,13 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
   bool IsConsteval = false;
   SourceLocation NotLocation;
   SourceLocation ConstevalLoc;
+  SourceLocation ConstexprLoc;
 
   if (Tok.is(tok::kw_constexpr)) {
     Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if
                                         : diag::ext_constexpr_if);
     IsConstexpr = true;
-    ConsumeToken();
+    ConstexprLoc = ConsumeToken();
   } else {
     if (Tok.is(tok::exclaim)) {
       NotLocation = ConsumeToken();
@@ -1515,7 +1515,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
     if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
                                   IsConstexpr ? Sema::ConditionKind::ConstexprIf
                                               : Sema::ConditionKind::Boolean,
-                                  LParen, RParen))
+                                  LParen, RParen, ConstexprLoc))
       return StmtError();
 
     if (IsConstexpr)
@@ -1558,11 +1558,16 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
     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);
   }
 
@@ -1603,11 +1608,16 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
     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())

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 1d56c495e899722..5fe8c1afec76ff3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -14832,7 +14832,8 @@ static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
 static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
                                     SourceLocation CC,
                                     bool *ICContext = nullptr,
-                                    bool IsListInit = false) {
+                                    bool IsListInit = false,
+                                    bool IsConstexprInit = false) {
   if (E->isTypeDependent() || E->isValueDependent()) return;
 
   const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
@@ -15141,11 +15142,14 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
           SmallString<32> PrettyTargetValue;
           TargetFloatValue.toString(PrettyTargetValue, TargetPrecision);
 
-          S.DiagRuntimeBehavior(
-              E->getExprLoc(), E,
+          PartialDiagnostic PD =
               S.PDiag(diag::warn_impcast_integer_float_precision_constant)
-                  << PrettySourceValue << PrettyTargetValue << E->getType() << T
-                  << E->getSourceRange() << clang::SourceRange(CC));
+              << PrettySourceValue << PrettyTargetValue << E->getType() << T
+              << E->getSourceRange() << clang::SourceRange(CC);
+          if (IsConstexprInit)
+            S.Diag(E->getExprLoc(), PD);
+          else
+            S.DiagRuntimeBehavior(E->getExprLoc(), E, PD);
         }
       } else {
         // Otherwise, the implicit conversion may lose precision.
@@ -15199,11 +15203,14 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
       std::string PrettySourceValue = toString(Value, 10);
       std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
 
-      S.DiagRuntimeBehavior(
-          E->getExprLoc(), E,
+      PartialDiagnostic PD =
           S.PDiag(diag::warn_impcast_integer_precision_constant)
-              << PrettySourceValue << PrettyTargetValue << E->getType() << T
-              << E->getSourceRange() << SourceRange(CC));
+          << PrettySourceValue << PrettyTargetValue << E->getType() << T
+          << E->getSourceRange() << SourceRange(CC);
+      if (IsConstexprInit)
+        S.Diag(E->getExprLoc(), PD);
+      else
+        S.DiagRuntimeBehavior(E->getExprLoc(), E, PD);
       return;
     }
 
@@ -15245,11 +15252,14 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
         std::string PrettySourceValue = toString(Value, 10);
         std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
 
-        S.DiagRuntimeBehavior(
-            E->getExprLoc(), E,
+        PartialDiagnostic PD =
             S.PDiag(diag::warn_impcast_integer_precision_constant)
-                << PrettySourceValue << PrettyTargetValue << E->getType() << T
-                << E->getSourceRange() << SourceRange(CC));
+            << PrettySourceValue << PrettyTargetValue << E->getType() << T
+            << E->getSourceRange() << SourceRange(CC);
+        if (IsConstexprInit)
+          S.Diag(E->getExprLoc(), PD);
+        else
+          S.DiagRuntimeBehavior(E->getExprLoc(), E, PD);
         return;
       }
     }
@@ -15411,6 +15421,17 @@ static void AnalyzeImplicitConversions(
     if (auto *Src = OVE->getSourceExpr())
       SourceExpr = Src;
 
+  bool IsConstexprInit =
+      S.isConstantEvaluated() &&
+      isa_and_present<VarDecl>(S.ExprEvalContexts.back().ManglingContextDecl);
+  // Constant-evaluated initializers are not diagnosed by DiagRuntimeBehavior,
+  // but narrowings from the evaluated result to the variable type should be
+  // diagnosed.
+  if (IsConstexprInit && SourceExpr->getType() != T) {
+    CheckImplicitConversion(S, SourceExpr, T, CC, nullptr, IsListInit,
+                            /*IsConstexprInit=*/true);
+  }
+
   if (const auto *UO = dyn_cast<UnaryOperator>(SourceExpr))
     if (UO->getOpcode() == UO_Not &&
         UO->getSubExpr()->isKnownToHaveBooleanValue())
@@ -15446,7 +15467,7 @@ static void AnalyzeImplicitConversions(
   // Go ahead and check any implicit conversions we might have skipped.
   // The non-canonical typecheck is just an optimization;
   // CheckImplicitConversion will filter out dead implicit conversions.
-  if (SourceExpr->getType() != T)
+  if (!IsConstexprInit && SourceExpr->getType() != T)
     CheckImplicitConversion(S, SourceExpr, T, CC, nullptr, IsListInit);
 
   // Now continue drilling into this expression.

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7d92e93188610c0..30e4af16944ab5f 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15443,7 +15443,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
 
   // 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
@@ -15451,6 +15451,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
     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

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 0091e0ecf6f3986..3d5ecfc2eb2562a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18241,15 +18241,6 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) {
     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<VarDecl>(D))
-    return Var->hasGlobalStorage();
-
-  return false;
-}
-
 /// Invoked when we are about to parse an initializer for the declaration
 /// 'Dcl'.
 ///
@@ -18272,9 +18263,6 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
   // 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.
@@ -18283,9 +18271,6 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
   if (!D || D->isInvalidDecl())
     return;
 
-  if (isNonlocalVariable(D))
-    PopExpressionEvaluationContext();
-
   if (S && D->isOutOfLine())
     ExitDeclaratorContext(S);
 }

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 92496b03ecabe54..305b43743774788 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7091,6 +7091,32 @@ static void DiagnosedUnqualifiedCallsToStdFunctions(Sema &S,
       << 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 DiagnoseTautologicalCallToIsConstantEvaluated(Sema &S,
+                                                          const CallExpr *CE) {
+  if (S.inTemplateInstantiation() || CE->getBeginLoc().isMacroID())
+    return;
+  if (const FunctionDecl *FD = CE->getDirectCallee()) {
+    bool IsBuiltin =
+        FD->getBuiltinID() == Builtin::BI__builtin_is_constant_evaluated;
+    SourceLocation ConstexprIfLoc = S.ConstexprIfLoc;
+
+    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_tautological_is_constant_evaluated)
+            << IsBuiltin << AlwaysTrue
+            << FixItHint::CreateRemoval(ConstexprIfLoc);
+    }
+  }
+}
+
 ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
                                MultiExprArg ArgExprs, SourceLocation RParenLoc,
                                Expr *ExecConfig) {
@@ -7115,8 +7141,10 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
     Call = ActOnOpenMPCall(Call, Scope, LParenLoc, ArgExprs, RParenLoc,
                            ExecConfig);
   if (LangOpts.CPlusPlus) {
-    if (const auto *CE = dyn_cast<CallExpr>(Call.get()))
+    if (const auto *CE = dyn_cast<CallExpr>(Call.get())) {
       DiagnosedUnqualifiedCallsToStdFunctions(*this, CE);
+      DiagnoseTautologicalCallToIsConstantEvaluated(*this, CE);
+    }
   }
   return Call;
 }
@@ -18608,6 +18636,8 @@ void Sema::PopExpressionEvaluationContext() {
       } else
         llvm_unreachable("Couldn't infer lambda error message.");
 
+      if (auto *VD = dyn_cast_if_present<VarDecl>(Rec.ManglingContextDecl))
+        VD->setInvalidDecl();
       for (const auto *L : Rec.Lambdas)
         Diag(L->getBeginLoc(), D);
     }

diff  --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 1702ddb3ee0fbf0..bd2c3c2f45d4c0c 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1444,12 +1444,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
 
   // Enter a new evaluation context to insulate the lambda from any
   // cleanups from the enclosing full-expression.
+  bool InImmediateFunctionContext = isImmediateFunctionContext();
   PushExpressionEvaluationContext(
-      LSI->CallOperator->isConsteval()
+      LSI->CallOperator->isConsteval() || InImmediateFunctionContext
           ? ExpressionEvaluationContext::ImmediateFunctionContext
           : ExpressionEvaluationContext::PotentiallyEvaluated);
   ExprEvalContexts.back().InImmediateFunctionContext =
-      LSI->CallOperator->isConsteval();
+      LSI->CallOperator->isConsteval() || InImmediateFunctionContext;
   ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
       getLangOpts().CPlusPlus20 && LSI->CallOperator->isImmediateEscalating();
 }

diff  --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 10adfbc406dfbb5..c20d0c50b09e1fe 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -933,16 +933,14 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc,
   }
 
   if (ConstevalOrNegatedConsteval) {
-    bool Immediate = ExprEvalContexts.back().Context ==
-                     ExpressionEvaluationContext::ImmediateFunctionContext;
-    if (CurContext->isFunctionOrMethod()) {
-      const auto *FD =
-          dyn_cast<FunctionDecl>(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 || AlwaysFalse)
+      Diags.Report(IfLoc, diag::warn_tautological_consteval_if)
+          << (AlwaysTrue
+                  ? StatementKind == IfStatementKind::ConstevalNegated
+                  : StatementKind == IfStatementKind::ConstevalNonNegated);
   }
 
   return BuildIfStmt(IfLoc, StatementKind, LParenLoc, InitStmt, Cond, RParenLoc,

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index fa839e9b71a3cf9..c4f1c4e06ac83b3 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5378,8 +5378,11 @@ void Sema::InstantiateVariableInitializer(
     Var->setImplicitlyInline();
 
   if (OldVar->getInit()) {
-    EnterExpressionEvaluationContext Evaluated(
-        *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
+    Sema::ExpressionEvaluationContext InitEvalContext =
+        Var->isConstexpr()
+            ? Sema::ExpressionEvaluationContext::ConstantEvaluated
+            : Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
+    EnterExpressionEvaluationContext Evaluated(*this, InitEvalContext, Var);
 
     // Instantiate the initializer.
     ExprResult Init;

diff  --git a/clang/test/AST/Interp/builtins.cpp b/clang/test/AST/Interp/builtins.cpp
index 5e2ffe50f374057..90bd290f1d6a4ba 100644
--- a/clang/test/AST/Interp/builtins.cpp
+++ b/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
 

diff  --git a/clang/test/AST/Interp/if.cpp b/clang/test/AST/Interp/if.cpp
index 86ae8de6f73ebb7..3d1ed7b7ffe7623 100644
--- a/clang/test/AST/Interp/if.cpp
+++ b/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

diff  --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index aabc909b3328e48..67de4ef6dae2afa 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -225,15 +225,11 @@ namespace SizeOf {
 #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}} \
 

diff  --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index e3cd057baba75f5..596df90243b1e20 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -244,8 +244,8 @@ namespace UndefinedBehavior {
     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 expected-warning {{changes value from 200 to -56}}
+    constexpr signed char c2 = '\x64' * '\2'; // also ok expected-warning {{changes value from 200 to -56}}
     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

diff  --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp b/clang/test/CXX/expr/expr.const/p6-2a.cpp
index a937474d53b221c..7bcf6fdc3d99790 100644
--- a/clang/test/CXX/expr/expr.const/p6-2a.cpp
+++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp
@@ -43,12 +43,11 @@ struct Temporary {
 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

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
index db40bd5d1420ef3..8b30b5eefd85fc2 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
@@ -16,4 +16,5 @@ constexpr auto literal = []{};
 #if __cplusplus < 201703L
 // expected-error at -2 {{constexpr variable cannot have non-literal type}}
 // expected-note at -3 {{lambda closure types are non-literal types before C++17}}
+// expected-error at -4 {{a lambda expression may not appear inside of a constant expression}}
 #endif

diff  --git a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p4.cpp b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p4.cpp
index 8d43be6fc904781..fd2deee249016c2 100644
--- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p4.cpp
+++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p4.cpp
@@ -38,7 +38,8 @@ void test_consteval() {
   }() == 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() {
 }
 
 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_jumps() {
 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 @@ constexpr int h(int i) { // expected-note {{declared here}}
 }
 
 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 {

diff  --git a/clang/test/Parser/pragma-fenv_access.c b/clang/test/Parser/pragma-fenv_access.c
index 76256cff1b49b54..a626453344ee6e8 100644
--- a/clang/test/Parser/pragma-fenv_access.c
+++ b/clang/test/Parser/pragma-fenv_access.c
@@ -33,7 +33,7 @@ int main(void) {
   CONST float fnot_too_big = not_too_big;
   CONST int too_big = 0x7ffffff0;
 #if defined(CPP)
-//expected-warning at +2{{implicit conversion}}
+//expected-warning at +2{{implicit conversion from 'const int' to 'const float' changes value from 2147483632 to 2147483648}}
 #endif
   CONST float fbig = too_big; // inexact
 #if !defined(CPP)

diff  --git a/clang/test/SemaCXX/constant-conversion.cpp b/clang/test/SemaCXX/constant-conversion.cpp
index 9be8b139e79e228..884166c419764b7 100644
--- a/clang/test/SemaCXX/constant-conversion.cpp
+++ b/clang/test/SemaCXX/constant-conversion.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -triple x86_64-apple-darwin %s
 
 // This file tests -Wconstant-conversion, a subcategory of -Wconversion
 // which is on by default.
@@ -31,3 +31,59 @@ void test_bitfield() {
   s.one_bit = 1;    // expected-warning {{implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1}}
   s.one_bit = true; // no-warning
 }
+
+namespace Initializers {
+constexpr char ok = true ? 0 : 200;
+constexpr char a = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
+char b = 200; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
+const char c = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
+
+void f() {
+  constexpr char a = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
+  char b = 200; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
+  const char c = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
+  static char d = 2 * 100; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
+}
+
+constexpr void g() {
+  constexpr char a = 2 * 100; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
+  char b = 2 * 100; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
+  const char c = 2 * 100; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
+}
+
+consteval void h() {
+  char ok = true ? 0 : 200;
+  constexpr char a = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
+  char b = 200; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
+  const char c = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
+}
+
+template <int N>
+int templ() {
+  constexpr char a = false ? 129 : N; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}} \
+                                      // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 345 to 89}}
+  return 3;
+}
+
+void call_templ() {
+  int ok = templ<127>();
+  int l = templ<3>();
+  int m = templ<200>(); // expected-note {{in instantiation of}}
+  int n = templ<345>(); // expected-note {{in instantiation of}}
+}
+
+template <int a, int b>
+constexpr signed char 
diff  = a > b ? a - b : b - a; // expected-warning{{changes value from 201 to -55}} \
+                                                    // expected-warning{{changes value from 199 to -57}} \
+                                                    // expected-warning{{changes value from 299 to 43}} \
+                                                    // expected-warning{{changes value from 301 to 45}}
+
+void test_
diff () {
+  char ok1 = 
diff <201, 100>;
+  char ok2 = 
diff <101, 200>;
+  char s1 = 
diff <301, 100>; // expected-note {{in instantiation of}}
+  char s2 = 
diff <101, 300>; // expected-note {{in instantiation of}}
+  char w1 = 
diff <101, 400>; // expected-note {{in instantiation of}}
+  char w2 = 
diff <401, 100>; // expected-note {{in instantiation of}}
+}
+}

diff  --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 89d1b3ea6de05ea..8e6af7811a30b39 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1961,7 +1961,7 @@ namespace ConstexprConstructorRecovery {
 
 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}}
   }
 

diff  --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index a091fadfa3094bd..823778f25e16720 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -713,7 +713,7 @@ constexpr derp d;
 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 s = a.operator[](1);
 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 @@ struct tester {
 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 @@ auto V1 = make_name(pad(bad)); // expected-error {{call to consteval function 'G
 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}}
 }
 }
@@ -1133,7 +1131,7 @@ namespace GH65985 {
 int consteval operator""_foo(unsigned long long V) {
     return 0;
 }
-int consteval operator""_bar(unsigned long long V); // expected-note 3{{here}}
+int consteval operator""_bar(unsigned long long V); // expected-note 2{{here}}
 
 int consteval f() {
   return 0;
@@ -1149,10 +1147,7 @@ struct C {
                                 // expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \
                                 // expected-error {{in-class initializer for static data member is not a constant expression}}
 
-    // FIXME: remove duplicate diagnostics
-    static constexpr int d = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \
-                                    // expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \
-                                    // expected-error {{constexpr variable 'd' must be initialized by a constant expression}}  \
+    static constexpr int d = 1_bar; // expected-error {{constexpr variable 'd' must be initialized by a constant expression}}  \
                                     // expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}}
 
     static const int e = f();
@@ -1167,12 +1162,12 @@ namespace GH66562 {
 
 namespace ns
 {
-    consteval int foo(int x) { return 1; } // expected-note {{declared here}}
+    consteval int foo(int x) { return 1; }
 }
 
 template <class A>
 struct T {
-    static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}}
+    static constexpr auto xx = ns::foo(A{});
 };
 
 }

diff  --git a/clang/test/SemaCXX/cxx2b-consteval-if.cpp b/clang/test/SemaCXX/cxx2b-consteval-if.cpp
index 72ba58b676247f8..21413e58169b665 100644
--- a/clang/test/SemaCXX/cxx2b-consteval-if.cpp
+++ b/clang/test/SemaCXX/cxx2b-consteval-if.cpp
@@ -18,7 +18,7 @@ constexpr auto h() {
 
 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;

diff  --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
index 531a62622873357..2daab2c75322c40 100644
--- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
+++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
@@ -209,7 +209,7 @@ struct SS {
 SS::SS(){} // expected-note {{in the default initializer of 'x'}}
 
 consteval int f2(int x) {
-    if (!__builtin_is_constant_evaluated()) side_effect();
+    if (!__builtin_is_constant_evaluated()) side_effect(); // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to true}}
     return x;
 }
 struct S2 {
@@ -332,16 +332,14 @@ S s(0); // expected-note {{in the default initializer of 'j'}}
 }
 
 namespace GH65985 {
-consteval int invalid(); // expected-note 2{{declared here}}
+consteval int invalid(); // expected-note {{declared here}}
 constexpr int escalating(auto) {
     return invalid();
-    // expected-note at -1 {{'escalating<int>' is an immediate function because its body contains a call to a consteval function 'invalid' and that call is not a constant expression}}
-    // expected-note at -2 2{{undefined function 'invalid' cannot be used in a constant expression}}
+    // expected-note at -1 {{undefined function 'invalid' cannot be used in a constant expression}}
 }
 struct S {
-    static constexpr int a = escalating(0); // expected-note 2{{in call to}}
-    // expected-error at -1 {{call to immediate function 'GH65985::escalating<int>' is not a constant expression}}
-    // expected-error at -2 {{constexpr variable 'a' must be initialized by a constant expression}}
+    static constexpr int a = escalating(0); // expected-note {{in call to}}
+    // expected-error at -1 {{constexpr variable 'a' must be initialized by a constant expression}}
 };
 
 }

diff  --git a/clang/test/SemaCXX/fixit-tautological-meta-constant.cpp b/clang/test/SemaCXX/fixit-tautological-meta-constant.cpp
new file mode 100644
index 000000000000000..104dd2e75d25ab4
--- /dev/null
+++ b/clang/test/SemaCXX/fixit-tautological-meta-constant.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++2b -Wno-unused-value -fdiagnostics-parseable-fixits -fsyntax-only %s 2>&1 | FileCheck %s
+namespace std {
+constexpr inline bool
+  is_constant_evaluated() noexcept {
+    if consteval { return true; } else { return false; }
+  }
+} // namespace std
+
+constexpr void cexpr() {
+  if constexpr (std::is_constant_evaluated()) {}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:16}:""
+  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:6-[[@LINE-2]]:16}:""
+  constexpr int a = std::is_constant_evaluated();
+  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:{{.*}}-[[@LINE-1]]:{{.*}}}:""
+
+  if constexpr (const int ce = __builtin_is_constant_evaluated()) {}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:16}:""
+  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:6-[[@LINE-2]]:16}:""
+  constexpr int b = std::is_constant_evaluated();
+  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:{{.*}}-[[@LINE-1]]:{{.*}}}:""
+}

diff  --git a/clang/test/SemaCXX/vartemplate-lambda.cpp b/clang/test/SemaCXX/vartemplate-lambda.cpp
index d2b53b53dcd4922..ab187b2c2e7a2b3 100644
--- a/clang/test/SemaCXX/vartemplate-lambda.cpp
+++ b/clang/test/SemaCXX/vartemplate-lambda.cpp
@@ -12,7 +12,7 @@ template<typename T> auto v1 = [](int a = T()) { return a; }();
 
 struct S {
   template<class T>
-  static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't<int>' 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{{a lambda expression may not appear inside of a constant expression}}
 };
 
 template <typename X>
@@ -21,7 +21,7 @@ int foo2() {
   fn1<char>(a);
   (void)v1<int>;
   (void)v1<int *>; // expected-note{{in instantiation of variable template specialization 'v1' requested here}}
-  (void)S::t<int>; // expected-note{{in instantiation of static data member 'S::t<int>' requested here}}
+  (void)S::t<int>;
   return 0;
 }
 

diff  --git a/clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp b/clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp
index 35dc69cccb3a2e2..6ee5f86998eb606 100644
--- a/clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp
+++ b/clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp
@@ -7,35 +7,35 @@ constexpr bool is_constant_evaluated() noexcept {
 } // 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;

diff  --git a/clang/test/SemaCXX/warn-tautological-meta-constant.cpp b/clang/test/SemaCXX/warn-tautological-meta-constant.cpp
new file mode 100644
index 000000000000000..eef944effd8eb8c
--- /dev/null
+++ b/clang/test/SemaCXX/warn-tautological-meta-constant.cpp
@@ -0,0 +1,262 @@
+// RUN: %clang_cc1 -std=c++2b -Wno-unused-value -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;}
+  }();
+  auto lamda = []() {
+    if consteval {return 8;}
+    else {return 4;}
+  };
+  constexpr auto cexpr_lambda = []() {
+    if consteval {}
+    return __builtin_is_constant_evaluated();
+  };
+  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 <bool b>
+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<std::is_constant_evaluated()>() { // 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<false>();
+}
+
+static_assert([] {
+    if consteval {
+      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 <bool c = std::is_constant_evaluated()> // expected-warning {{always evaluate to true}}
+void vvv() {
+  return;
+}
+
+template<> void vvv<true>() {}
+template<> void vvv<false>() {}
+
+template<typename T> 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}}
+  }
+};
+
+namespace condition {
+void f() {
+  if constexpr (int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to false}}
+                true) {}
+  if constexpr (const int a = __builtin_is_constant_evaluated();
+                true) {}
+  if constexpr (constexpr int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
+                true) {}
+  if constexpr (;const int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+  if constexpr (;constexpr int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+
+  if (int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to false}}
+      true) {}
+  if (const int a = __builtin_is_constant_evaluated();
+      true) {}
+  if (constexpr int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
+      true) {}
+  if (;int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to false}}
+  if (;const int b = __builtin_is_constant_evaluated()) {}
+  if (;constexpr int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+
+  if constexpr (__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+  if (__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to false}}
+
+  if constexpr (__builtin_is_constant_evaluated(); true) {} // expected-warning {{always evaluate to false}}
+  // False
+  if constexpr (({__builtin_is_constant_evaluated();2;3;}); true) {}
+
+  if (__builtin_is_constant_evaluated(); true) {} // expected-warning {{always evaluate to false}}
+  if constexpr (;__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+  if (;__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to false}}
+}
+
+constexpr void g() {
+  if constexpr (int a = __builtin_is_constant_evaluated();
+                true) {}
+  if constexpr (const int a = __builtin_is_constant_evaluated();
+                true) {}
+  if constexpr (constexpr int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
+                true) {}
+  if constexpr (;const int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+  if constexpr (;constexpr int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+
+  if (int a = __builtin_is_constant_evaluated();
+      true) {}
+  if (const int a = __builtin_is_constant_evaluated();
+      true) {}
+  if (constexpr int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
+      true) {}
+  if (;int b = __builtin_is_constant_evaluated()) {}
+  if (;const int b = __builtin_is_constant_evaluated()) {}
+  if (;constexpr int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+
+  if constexpr (__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+  if (__builtin_is_constant_evaluated()) {}
+
+  if constexpr (__builtin_is_constant_evaluated(); true) {}
+  if constexpr (({__builtin_is_constant_evaluated();2;3;}); true) {}
+
+  if (__builtin_is_constant_evaluated(); true) {}
+  if constexpr (;__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
+  if (;__builtin_is_constant_evaluated()) {}
+}
+}
+
+namespace Arguments {
+  int nonc(int n) { return n;}
+  constexpr int cexpr(int n) { return n;}
+  consteval int ceval(int n) { return n; }
+  void f() {
+    // FIXME: These are tauologically-false;
+    int a1 = nonc(__builtin_is_constant_evaluated());
+    const int b1 = nonc(__builtin_is_constant_evaluated());
+    int a2 = cexpr(__builtin_is_constant_evaluated());
+
+    // ok
+    const int b2 = cexpr(__builtin_is_constant_evaluated());
+    constexpr int c2 = cexpr(__builtin_is_constant_evaluated()); // expected-warning {{always evaluate to true}}
+
+    // FIXME: These are tautologically-true;
+    int a3 = ceval(__builtin_is_constant_evaluated());
+    const int b3 = ceval(__builtin_is_constant_evaluated());
+
+    // ok
+    constexpr int c3 = ceval(__builtin_is_constant_evaluated()); // expected-warning {{always evaluate to true}}
+  }
+}

diff  --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index e98ebcc9203a430..c90339e778bc182 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -135,21 +135,21 @@ namespace PackInTypeConstraint {
 
 namespace BuiltinIsConstantEvaluated {
   // Check that we do all satisfaction and diagnostic checks in a constant context.
-  template<typename T> concept C = __builtin_is_constant_evaluated(); // expected-warning {{always}}
+  template<typename T> concept C = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
   static_assert(C<int>);
 
-  template<typename T> concept D = __builtin_is_constant_evaluated() == true; // expected-warning {{always}}
+  template<typename T> concept D = __builtin_is_constant_evaluated() == true; // expected-warning {{always evaluate to true}}
   static_assert(D<int>);
 
-  template<typename T> concept E = __builtin_is_constant_evaluated() == true && // expected-warning {{always}}
+  template<typename T> concept E = __builtin_is_constant_evaluated() == true && // expected-warning {{always evaluate to true}}
                                    false; // expected-note {{'false' evaluated to false}}
   static_assert(E<int>); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'E'}}
 
-  template<typename T> concept F = __builtin_is_constant_evaluated() == false; // expected-warning {{always}}
+  template<typename T> concept F = __builtin_is_constant_evaluated() == false; // expected-warning {{always evaluate to true}}
   // expected-note at -1 {{'__builtin_is_constant_evaluated() == false' (1 == 0)}}
   static_assert(F<int>); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'F'}}
 
-  template<typename T> concept G = __builtin_is_constant_evaluated() && // expected-warning {{always}}
+  template<typename T> concept G = __builtin_is_constant_evaluated() && // expected-warning {{always evaluate to true}}
                                    false; // expected-note {{'false' evaluated to false}}
   static_assert(G<int>); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'G'}}
 }

diff  --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index fdfbbfe4e3a9dff..85173b23fc6497e 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -188,7 +188,6 @@ Frontend
 | EvaluateAsBooleanCondition (<test.cc:8:21, col:25>)
 | | EvaluateAsRValue (<test.cc:8:21, col:25>)
 | EvaluateAsInitializer (slow_value)
-| EvaluateAsConstantExpr (<test.cc:17:33, col:59>)
 | EvaluateAsConstantExpr (<test.cc:18:11, col:37>)
 | EvaluateAsRValue (<test.cc:22:14, line:23:58>)
 | EvaluateAsInitializer (slow_init_list)

diff  --git a/libcxx/include/__type_traits/is_constant_evaluated.h b/libcxx/include/__type_traits/is_constant_evaluated.h
index d7af462486e1316..1649762ed6dc598 100644
--- a/libcxx/include/__type_traits/is_constant_evaluated.h
+++ b/libcxx/include/__type_traits/is_constant_evaluated.h
@@ -24,7 +24,14 @@ _LIBCPP_INLINE_VISIBILITY inline constexpr bool is_constant_evaluated() noexcept
 #endif
 
 _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR bool __libcpp_is_constant_evaluated() _NOEXCEPT {
+// __builtin_is_constant_evaluated() in this function always evaluates to false in pre-C++11 mode
+// because this function is not constexpr-qualified.
+// The following macro use clarifies this and avoids warnings from compilers.
+#ifndef _LIBCPP_CXX03_LANG
   return __builtin_is_constant_evaluated();
+#else
+  return false;
+#endif
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp
index 9291c0aa1f43404..abb9157df9abbbb 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp
@@ -93,12 +93,10 @@ constexpr void test_join_view() {
 }
 
 int main(int, char**) {
-  if (!std::is_constant_evaluated()) {
-    test_containers<std::deque<int>, std::deque<int>>();
-    test_containers<std::deque<int>, std::vector<int>>();
-    test_containers<std::vector<int>, std::deque<int>>();
-    test_containers<std::vector<int>, std::vector<int>>();
-  }
+  test_containers<std::deque<int>, std::deque<int>>();
+  test_containers<std::deque<int>, std::vector<int>>();
+  test_containers<std::vector<int>, std::deque<int>>();
+  test_containers<std::vector<int>, std::vector<int>>();
 
   types::for_each(types::forward_iterator_list<int*>{}, []<class Iter> {
     test_join_view<Iter, Iter>();

diff  --git a/libcxx/test/std/utilities/meta/meta.const.eval/is_constant_evaluated.verify.cpp b/libcxx/test/std/utilities/meta/meta.const.eval/is_constant_evaluated.verify.cpp
index f4865ff368079be..ef6e6f18ba6b5ca 100644
--- a/libcxx/test/std/utilities/meta/meta.const.eval/is_constant_evaluated.verify.cpp
+++ b/libcxx/test/std/utilities/meta/meta.const.eval/is_constant_evaluated.verify.cpp
@@ -24,7 +24,7 @@ int main(int, char**)
 #else
   // expected-error-re at +1 {{{{(static_assert|static assertion)}} failed}}
   static_assert(!std::is_constant_evaluated(), "");
-  // expected-warning at -1 0-1 {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
+  // expected-warning-re at -1 0-1 {{'std::is_constant_evaluated' will always evaluate to {{('true' in a manifestly constant-evaluated expression|true in this context)}}}}
 #endif
   return 0;
 }


        


More information about the cfe-commits mailing list