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