diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index b95a52199846f..bdb86322df663 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -59,12 +59,16 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, return; const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, - VD->getType()->isIntegralOrEnumerationType() - ? diag::note_constexpr_ltor_non_const_int - : diag::note_constexpr_ltor_non_constexpr, - 1) - << VD; + + if (VD->getType()->isIntegralOrEnumerationType()) + S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD; + else + S.FFDiag(Loc, + S.getLangOpts().CPlusPlus11 + ? diag::note_constexpr_ltor_non_constexpr + : diag::note_constexpr_ltor_non_integral, + 1) + << VD << VD->getType(); S.Note(VD->getLocation(), diag::note_declared_at); } @@ -231,12 +235,32 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { assert(Desc); + + auto IsConstType = [&S](const VarDecl *VD) -> bool { + if (VD->isConstexpr()) + return true; + + if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11) + return false; + + QualType T = VD->getType(); + if (T.isConstQualified()) + return true; + + if (const auto *RT = T->getAs()) + return RT->getPointeeType().isConstQualified(); + + if (const auto *PT = T->getAs()) + return PT->getPointeeType().isConstQualified(); + + return false; + }; + if (const auto *D = Desc->asValueDecl()) { if (const auto *VD = dyn_cast(D); - VD && VD->hasGlobalStorage() && - !(VD->isConstexpr() || VD->getType().isConstQualified())) { + VD && VD->hasGlobalStorage() && !IsConstType(VD)) { diagnoseNonConstVariable(S, OpPC, VD); - return false; + return S.inConstantContext(); } } diff --git a/clang/test/AST/Interp/cxx11.cpp b/clang/test/AST/Interp/cxx11.cpp new file mode 100644 index 0000000000000..81e293fec1750 --- /dev/null +++ b/clang/test/AST/Interp/cxx11.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 %s +// RUN: %clang_cc1 -verify=both,ref -std=c++11 %s + +// expected-no-diagnostics + +namespace IntOrEnum { + const int k = 0; + const int &p = k; + template struct S {}; + S

s; +} + +const int cval = 2; +template struct C{}; +template struct C; + + +/// FIXME: This example does not get properly diagnosed in the new interpreter. +extern const int recurse1; +const int recurse2 = recurse1; // ref-note {{here}} +const int recurse1 = 1; +int array1[recurse1]; +int array2[recurse2]; // ref-warning 2{{variable length array}} \ + // ref-note {{initializer of 'recurse2' is not a constant expression}} diff --git a/clang/test/AST/Interp/cxx98.cpp b/clang/test/AST/Interp/cxx98.cpp new file mode 100644 index 0000000000000..79f93c8d78f16 --- /dev/null +++ b/clang/test/AST/Interp/cxx98.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++98 %s +// RUN: %clang_cc1 -verify=both,ref -std=c++98 %s + + + +namespace IntOrEnum { + const int k = 0; + const int &p = k; // both-note {{declared here}} + template struct S {}; + S

s; // both-error {{not an integral constant expression}} \ + // both-note {{read of variable 'p' of non-integral, non-enumeration type 'const int &'}} +} + +const int cval = 2; +template struct C{}; +template struct C; + + +/// FIXME: This example does not get properly diagnosed in the new interpreter. +extern const int recurse1; +const int recurse2 = recurse1; // ref-note {{here}} +const int recurse1 = 1; +int array1[recurse1]; +int array2[recurse2]; // ref-warning 2{{variable length array}} \ + // ref-note {{initializer of 'recurse2' is not a constant expression}} \ + // expected-warning {{variable length array}} \ + // expected-error {{variable length array}} + +int NCI; // both-note {{declared here}} +int NCIA[NCI]; // both-warning {{variable length array}} \ + // both-error {{variable length array}} \\ + // both-note {{read of non-const variable 'NCI'}}