loladiro created this revision.
loladiro added reviewers: EricWF, aaron.ballman, rsmith.
loladiro added a subscriber: cfe-commits.
loladiro set the repository for this revision to rL LLVM.

This hooks up the detailed diagnostics why constant initialization was not 
possible if require_constant_initialization reports an error. I have updated 
the test to account for the new notes.
Everything works fine, except that in C++11 mode we get:
```
error: 'note' diagnostics expected but not seen:
  File 
/data/llvm/tools/clang/test/SemaCXX/attr-require-constant-initialization.cpp 
Line 229 (directive at 
/data/llvm/tools/clang/test/SemaCXX/attr-require-constant-initialization.cpp:231):
 non-constexpr constructor 'NonLit' cannot be used in a constant expression
error: 'note' diagnostics seen but not expected:
  (frontend): non-literal type 'NonLit' cannot be used in a constant expression
```
This is because of an ImplicitValueInitExpr that gets passed into 
CheckLiteralType, but since ImplicitValueInitExpr doesn't have source 
information we get an invalid source location. I'm not really sure how to fix 
that (Is it possible to test for a note without source location?). Adding the 
proper source locations to ImplicitValueInitExpr seemed like a bigger 
undertaking than was warranted for this patch, so I'd appreciate guidance on 
how to proceed.

Repository:
  rL LLVM

https://reviews.llvm.org/D24371

Files:
  lib/Sema/SemaDecl.cpp
  test/SemaCXX/attr-require-constant-initialization.cpp

Index: test/SemaCXX/attr-require-constant-initialization.cpp
===================================================================
--- test/SemaCXX/attr-require-constant-initialization.cpp
+++ test/SemaCXX/attr-require-constant-initialization.cpp
@@ -7,9 +7,9 @@
 
 #define ATTR __attribute__((require_constant_initialization)) // expected-note 0+ {{expanded from macro}}
 
-int ReturnInt();
+int ReturnInt(); // expected-note 0+ {{declared here}}
 
-struct PODType {
+struct PODType { // expected-note 0+ {{declared here}}
   int value;
   int value2;
 };
@@ -20,17 +20,17 @@
 struct LitType {
   constexpr LitType() : value(0) {}
   constexpr LitType(int x) : value(x) {}
-  LitType(void *) : value(-1) {}
+  LitType(void *) : value(-1) {} // expected-note 0+ {{declared here}}
   int value;
 };
 #endif
 
-struct NonLit {
+struct NonLit { // expected-note 0+ {{declared here}}
 #if __cplusplus >= 201402L
   constexpr NonLit() : value(0) {}
   constexpr NonLit(int x) : value(x) {}
 #else
-  NonLit() : value(0) {}
+  NonLit() : value(0) {}  // expected-note 0+ {{declared here}}
   NonLit(int x) : value(x) {}
 #endif
   NonLit(void *) : value(-1) {}
@@ -82,23 +82,44 @@
   const int non_global = 42;
   ATTR static const int &local_init = non_global; // expected-error {{variable does not have a constant initializer}}
   // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+#if __cplusplus >= 201103L
+  // expected-note@-3 {{reference to 'non_global' is not a constant expression}}
+  // expected-note@-5 {{declared here}}
+#else
+  // expected-note@-6 {{subexpression not valid in a constant expression}}
+#endif
   ATTR static const int &global_init = glvalue_int;
   ATTR static const int &temp_init = 42;
 }
 
 ATTR const int &temp_ref = 42;
 ATTR const int &temp_ref2 = ReturnInt(); // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+#if __cplusplus >= 201103L
+// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
 ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+#if __cplusplus >= 201103L
+// expected-note@-3 {{non-literal type 'const NonLit' cannot be used in a constant expression}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
 
 #if __cplusplus >= 201103L
 ATTR const LitType &lit_temp_ref = 42;
 ATTR const int &subobj_ref = LitType{}.value;
 #endif
 
 ATTR const int &nl_subobj_ref = NonLit().value; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+#if __cplusplus >= 201103L
+// expected-note-re@-3 {{non-literal type '{{.*}}' cannot be used in a constant expression}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
 
 struct TT1 {
   ATTR static const int &no_init;
@@ -116,6 +137,8 @@
 #if __cplusplus >= 201103L
 thread_local const int &TT1::tl_glvalue_init = glvalue_int;
 thread_local const int &TT1::tl_temp_init = 42; // expected-error {{variable does not have a constant initializer}}
+// expected-note@-1 {{reference to temporary is not a constant expression}}
+// expected-note@-2 {{temporary created here}}
 #endif
 
 // [basic.start.static]p2.2
@@ -129,17 +152,21 @@
 #else
   ATTR static PODType pod; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'PODType' cannot be used in a constant expression}}
 #endif
   ATTR static PODType pot2 = {ReturnInt()}; // expected-error {{variable does not have a constant initializer}}
-                                            // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
-
+  // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
 #if __cplusplus >= 201103L
+  // expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
+
   constexpr LitType l;
   ATTR static LitType static_lit = l;
   ATTR static LitType static_lit2 = (void *)0; // expected-error {{variable does not have a constant initializer}}
   // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+  // expected-note@-2 {{non-constexpr constructor 'LitType' cannot be used in a constant expression}}
   ATTR static LitType static_lit3 = ReturnInt(); // expected-error {{variable does not have a constant initializer}}
   // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+  // expected-note@-2 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
   ATTR thread_local LitType tls = 42;
 #endif
 }
@@ -157,15 +184,21 @@
   ATTR static const NonLit non_lit_copy_init; // expected-note {{required by 'require_constant_initializer' attribute here}}
 #endif
 };
-PODType TT2::pod_noinit;
+PODType TT2::pod_noinit; // expected-note 0+ {{declared here}}
 #if __cplusplus >= 201103L
 // expected-error@-2 {{variable does not have a constant initializer}}
+// expected-note@-3 {{non-constexpr constructor 'PODType' cannot be used in a constant expression}}
 #endif
 PODType TT2::pod_copy_init(TT2::pod_noinit); // expected-error {{variable does not have a constant initializer}}
+#if __cplusplus >= 201103L
+// expected-note@-2 {{read of non-constexpr variable 'pod_noinit' is not allowed in a constant expression}}
+// expected-note@-3 {{in call to 'PODType(pod_noinit)'}}
+#endif
 #if __cplusplus >= 201402L
 const NonLit TT2::non_lit(42);
 const NonLit TT2::non_lit_list_init = {42};
 const NonLit TT2::non_lit_copy_init = 42; // expected-error {{variable does not have a constant initializer}}
+// expected-note@-1 {{subexpression not valid in a constant expression}}
 #endif
 
 #if __cplusplus >= 201103L
@@ -183,19 +216,25 @@
 #else
 ATTR NonLit nl_ctor; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
 ATTR NonLit nl_ctor2{}; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
 ATTR NonLit nl_ctor3 = {}; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
 ATTR thread_local NonLit nl_ctor_tl = {}; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
 ATTR StoresNonLit snl; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
 #endif
 
 // Non-literal types cannot appear in the initializer of a non-literal type.
 ATTR int nl_in_init = NonLit{42}.value; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{subexpression not valid in a constant expression}}
 ATTR int lit_in_init = LitType{42}.value;
 #endif
 
@@ -218,8 +257,9 @@
 ATTR PODType pod_full_init = {1, 2};
 ATTR PODType pod_non_constexpr_init = {1, ReturnInt()}; // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
-
 #if __cplusplus >= 201103L
+// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
+
 ATTR int val_init{};
 ATTR int brace_init = {};
 #endif
@@ -233,15 +273,17 @@
 // initializer
 struct NotC {
   constexpr NotC(void *) {}
-  NotC(int) {}
+  NotC(int) {} // expected-note {{declared here}}
 };
 template <class T>
 struct TestCtor {
   constexpr TestCtor(int x) : value(x) {}
+  // expected-note@-1 {{non-constexpr constructor 'NotC' cannot be used in a constant expression}}
   T value;
 };
 ATTR TestCtor<NotC> t(42); // expected-error {{variable does not have a constant initializer}}
 // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{in call to 'TestCtor(42)'}}
 #endif
 
 // Test various array types
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -10532,6 +10532,12 @@
           << Init->getSourceRange();
         Diag(attr->getLocation(), diag::note_declared_required_constant_init_here)
           << attr->getRange();
+        APValue Value;
+        SmallVector<PartialDiagnosticAt, 8> Notes;
+        cast<Expr>(var->ensureEvaluatedStmt()->Value)->EvaluateAsInitializer(
+          Value, getASTContext(), var, Notes);
+        for (auto &it : Notes)
+          Diag(it.first, it.second);
       }
     }
     else if (!var->isConstexpr() && IsGlobal &&
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to