This revision was automatically updated to reflect the committed changes.
Closed by commit rG924acb624f58: [clang] Prevent folding of non-const compound 
expr (authored by serge-sans-paille).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124038

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaTemplate/constexpr-instantiate.cpp


Index: clang/test/SemaTemplate/constexpr-instantiate.cpp
===================================================================
--- clang/test/SemaTemplate/constexpr-instantiate.cpp
+++ clang/test/SemaTemplate/constexpr-instantiate.cpp
@@ -219,7 +219,9 @@
       static int n;
     };
     template<const int *N> struct B {};
-    template<int N> constexpr int A<N>::k = *(int[N]){N}; // expected-error 
1+{{negative}}
+    template <int N> constexpr int A<N>::k = *(int[N]){N}; // expected-error 
1+{{negative}} expected-note 1+{{not valid in a constant expression}} 
expected-note 1+{{declared here}}
+    // expected-error@-1 1+{{must be initialized by a constant expression}}
+
     template<int N> int A<N>::n = *(int[N]){0};
 
     template <typename> void f() {
@@ -230,9 +232,9 @@
     };
 
     decltype(A<-3>::k) d1 = 0; // ok
-    decltype(char{A<-4>::k}) d2 = 0; // expected-note {{instantiation of }} 
expected-error {{narrow}} expected-note {{cast}}
-    decltype(char{A<1>::k}) d3 = 0; // ok
-    decltype(char{A<1 + (unsigned char)-1>::k}) d4 = 0; // expected-error 
{{narrow}} expected-note {{cast}}
+    decltype(char{A<-4>::k}) d2 = 0;                    // expected-note 
1+{{instantiation of }} expected-error {{narrow}} expected-note {{cast}}
+    decltype(char{A<1>::k}) d3 = 0;                     // expected-note 
1+{{instantiation of }} expected-error {{narrow}} expected-note {{cast}}
+    decltype(char{A<1 + (unsigned char)-1>::k}) d4 = 0; // expected-error 
{{narrow}} expected-note {{cast}}  expected-note {{instantiation of}}
   }
 }
 
Index: clang/test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1596,8 +1596,13 @@
   // Matching GCC, file-scope array compound literals initialized by constants
   // are lifetime-extended.
   constexpr int *p = (int*)(int[1]){3}; // expected-warning {{C99}}
-  static_assert(*p == 3, "");
+  static_assert(*p == 3, "");           // expected-error {{static_assert 
expression is not an integral constant expression}}
+                                        // expected-note@-1 {{subexpression 
not valid}}
+                                        // expected-note@-3 {{declared here}}
   static_assert((int[2]){1, 2}[1] == 2, ""); // expected-warning {{C99}}
+  // expected-error@-1 {{static_assert expression is not an integral constant 
expression}}
+  // expected-note@-2 {{subexpression not valid}}
+  // expected-note@-3 {{declared here}}
 
   // Other kinds are not.
   struct X { int a[2]; };
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4259,9 +4259,33 @@
         Info.FFDiag(Conv);
         return false;
       }
+
       APValue Lit;
       if (!Evaluate(Lit, Info, CLE->getInitializer()))
         return false;
+
+      // According to GCC info page:
+      //
+      // 6.28 Compound Literals
+      //
+      // As an optimization, G++ sometimes gives array compound literals longer
+      // lifetimes: when the array either appears outside a function or has a
+      // const-qualified type. If foo and its initializer had elements of type
+      // char *const rather than char *, or if foo were a global variable, the
+      // array would have static storage duration. But it is probably safest
+      // just to avoid the use of array compound literals in C++ code.
+      //
+      // Obey that rule by checking constness for converted array types.
+
+      QualType CLETy = CLE->getType();
+      if (CLETy->isArrayType() && !Type->isArrayType()) {
+        if (!CLETy.isConstant(Info.Ctx)) {
+          Info.FFDiag(Conv);
+          Info.Note(CLE->getExprLoc(), diag::note_declared_at);
+          return false;
+        }
+      }
+
       CompleteObject LitObj(LVal.Base, &Lit, Base->getType());
       return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal, AK);
     } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {


Index: clang/test/SemaTemplate/constexpr-instantiate.cpp
===================================================================
--- clang/test/SemaTemplate/constexpr-instantiate.cpp
+++ clang/test/SemaTemplate/constexpr-instantiate.cpp
@@ -219,7 +219,9 @@
       static int n;
     };
     template<const int *N> struct B {};
-    template<int N> constexpr int A<N>::k = *(int[N]){N}; // expected-error 1+{{negative}}
+    template <int N> constexpr int A<N>::k = *(int[N]){N}; // expected-error 1+{{negative}} expected-note 1+{{not valid in a constant expression}} expected-note 1+{{declared here}}
+    // expected-error@-1 1+{{must be initialized by a constant expression}}
+
     template<int N> int A<N>::n = *(int[N]){0};
 
     template <typename> void f() {
@@ -230,9 +232,9 @@
     };
 
     decltype(A<-3>::k) d1 = 0; // ok
-    decltype(char{A<-4>::k}) d2 = 0; // expected-note {{instantiation of }} expected-error {{narrow}} expected-note {{cast}}
-    decltype(char{A<1>::k}) d3 = 0; // ok
-    decltype(char{A<1 + (unsigned char)-1>::k}) d4 = 0; // expected-error {{narrow}} expected-note {{cast}}
+    decltype(char{A<-4>::k}) d2 = 0;                    // expected-note 1+{{instantiation of }} expected-error {{narrow}} expected-note {{cast}}
+    decltype(char{A<1>::k}) d3 = 0;                     // expected-note 1+{{instantiation of }} expected-error {{narrow}} expected-note {{cast}}
+    decltype(char{A<1 + (unsigned char)-1>::k}) d4 = 0; // expected-error {{narrow}} expected-note {{cast}}  expected-note {{instantiation of}}
   }
 }
 
Index: clang/test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1596,8 +1596,13 @@
   // Matching GCC, file-scope array compound literals initialized by constants
   // are lifetime-extended.
   constexpr int *p = (int*)(int[1]){3}; // expected-warning {{C99}}
-  static_assert(*p == 3, "");
+  static_assert(*p == 3, "");           // expected-error {{static_assert expression is not an integral constant expression}}
+                                        // expected-note@-1 {{subexpression not valid}}
+                                        // expected-note@-3 {{declared here}}
   static_assert((int[2]){1, 2}[1] == 2, ""); // expected-warning {{C99}}
+  // expected-error@-1 {{static_assert expression is not an integral constant expression}}
+  // expected-note@-2 {{subexpression not valid}}
+  // expected-note@-3 {{declared here}}
 
   // Other kinds are not.
   struct X { int a[2]; };
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4259,9 +4259,33 @@
         Info.FFDiag(Conv);
         return false;
       }
+
       APValue Lit;
       if (!Evaluate(Lit, Info, CLE->getInitializer()))
         return false;
+
+      // According to GCC info page:
+      //
+      // 6.28 Compound Literals
+      //
+      // As an optimization, G++ sometimes gives array compound literals longer
+      // lifetimes: when the array either appears outside a function or has a
+      // const-qualified type. If foo and its initializer had elements of type
+      // char *const rather than char *, or if foo were a global variable, the
+      // array would have static storage duration. But it is probably safest
+      // just to avoid the use of array compound literals in C++ code.
+      //
+      // Obey that rule by checking constness for converted array types.
+
+      QualType CLETy = CLE->getType();
+      if (CLETy->isArrayType() && !Type->isArrayType()) {
+        if (!CLETy.isConstant(Info.Ctx)) {
+          Info.FFDiag(Conv);
+          Info.Note(CLE->getExprLoc(), diag::note_declared_at);
+          return false;
+        }
+      }
+
       CompleteObject LitObj(LVal.Base, &Lit, Base->getType());
       return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal, AK);
     } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to