hazohelet updated this revision to Diff 543510.
hazohelet marked 4 inline comments as done.
hazohelet added a comment.

Address comments from Corentin

- When emitting "lambda expression may not appear inside of a constant 
expression" error from `Sema::PopExpressionEvaluationContext`, mark the 
variable declaration as invalid if the popped context is initializer evaluation 
context.
- This stops constexpr evaluator from evaluating the initializer and emitting 
duplicate errors.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155064/new/

https://reviews.llvm.org/D155064

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticASTKinds.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ExprConstant.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.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/vartemplate-lambda.cpp
  clang/test/SemaCXX/warn-constant-evaluated-constexpr.cpp
  clang/test/SemaCXX/warn-tautological-meta-constant.cpp
  clang/test/SemaTemplate/concepts.cpp
  clang/unittests/Support/TimeProfilerTest.cpp
  
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

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-re@-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;
 }
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<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>();
Index: clang/unittests/Support/TimeProfilerTest.cpp
===================================================================
--- clang/unittests/Support/TimeProfilerTest.cpp
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -188,7 +188,6 @@
 | 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)
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<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@-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'}}
 }
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 <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 { // 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 <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}}
+  }
+};
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/vartemplate-lambda.cpp
===================================================================
--- clang/test/SemaCXX/vartemplate-lambda.cpp
+++ clang/test/SemaCXX/vartemplate-lambda.cpp
@@ -12,7 +12,7 @@
 
 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 @@
   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;
 }
 
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/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/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/constant-conversion.cpp
===================================================================
--- clang/test/SemaCXX/constant-conversion.cpp
+++ 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 @@
   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}}
+}
+}
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}}
+//expected-warning@+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)
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/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/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.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 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
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/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/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/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5372,8 +5372,11 @@
     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;
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -933,16 +933,14 @@
   }
 
   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,
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/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 DiagnoseTautologicalCallToIsConstantEvaluated(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_tautological_is_constant_evaluated)
+            << 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<CallExpr>(Call.get());
-    if (CE)
+    if (CE) {
       DiagnosedUnqualifiedCallsToStdFunctions(*this, CE);
+      DiagnoseTautologicalCallToIsConstantEvaluated(*this, CE);
+    }
   }
   return Call;
 }
@@ -18507,6 +18533,8 @@
       } 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);
     }
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -18105,15 +18105,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<VarDecl>(D))
-    return Var->hasGlobalStorage();
-
-  return false;
-}
-
 /// Invoked when we are about to parse an initializer for the declaration
 /// 'Dcl'.
 ///
@@ -18136,9 +18127,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.
@@ -18147,9 +18135,6 @@
   if (!D || D->isInvalidDecl())
     return;
 
-  if (isNonlocalVariable(D))
-    PopExpressionEvaluationContext();
-
   if (S && D->isOutOfLine())
     ExitDeclaratorContext(S);
 }
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/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -14633,7 +14633,8 @@
 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();
@@ -14942,11 +14943,14 @@
           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.
@@ -15000,11 +15004,14 @@
       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;
     }
 
@@ -15046,11 +15053,14 @@
         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;
       }
     }
@@ -15212,6 +15222,17 @@
     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())
@@ -15247,7 +15268,7 @@
   // 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.
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -1510,6 +1510,11 @@
   SourceLocation RParen;
   std::optional<bool> 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/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -3212,9 +3212,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<VarDecl>(D))
+    IsConstexpr = VD->isConstexpr();
+
   EnterExpressionEvaluationContext Context(
       Actions,
-      isa_and_present<FieldDecl>(D)
+      IsConstexpr ? Sema::ExpressionEvaluationContext::ConstantEvaluated
+      : isa_and_present<FieldDecl>(D)
           ? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed
           : Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
       D);
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<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.
@@ -2416,6 +2425,36 @@
       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;
@@ -2514,6 +2553,7 @@
             << getLangOpts().CPlusPlus20;
     } else {
       InitializerScopeRAII InitScope(*this, D, ThisDecl);
+      EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
 
       if (Tok.is(tok::code_completion)) {
         cutOffParsing();
@@ -2561,6 +2601,7 @@
     ExprVector Exprs;
 
     InitializerScopeRAII InitScope(*this, D, ThisDecl);
+    EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
 
     auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
     auto RunSignatureHelp = [&]() {
@@ -2611,6 +2652,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/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -12096,21 +12096,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/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1345,6 +1345,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;
 
@@ -1374,7 +1377,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/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1564,8 +1564,8 @@
   "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<
@@ -8843,6 +8843,9 @@
 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>;
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<DiagGroup<"constant-evaluated">>;
-
 // inline asm related.
 let CategoryName = "Inline Assembly Issue" in {
   def err_asm_invalid_escape : Error<
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -453,6 +453,12 @@
 - Clang now emits ``-Wconstant-logical-operand`` warning even when constant logical
   operand is on left side.
   (`#37919 <https://github.com/llvm/llvm-project/issues/37919>`_)
+- 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
 -------------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to