Author: Timm Bäder Date: 2024-04-11T19:05:29+02:00 New Revision: 64c3997939cf2d9b4fd1c24c89724d0b47afcd03
URL: https://github.com/llvm/llvm-project/commit/64c3997939cf2d9b4fd1c24c89724d0b47afcd03 DIFF: https://github.com/llvm/llvm-project/commit/64c3997939cf2d9b4fd1c24c89724d0b47afcd03.diff LOG: [clang][Interp] Allow initializing static class members We need to handle this when registering global variables. Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Program.cpp clang/test/AST/Interp/cxx23.cpp clang/test/AST/Interp/records.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 84bacd457c85b5..01ec31e4077f70 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -2778,26 +2778,34 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) { std::optional<PrimType> VarT = classify(VD->getType()); if (Context::shouldBeGloballyIndexed(VD)) { - // We've already seen and initialized this global. - if (P.getGlobal(VD)) - return true; - - std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init); - - if (!GlobalIndex) - return false; - - if (Init) { + auto initGlobal = [&](unsigned GlobalIndex) -> bool { + assert(Init); DeclScope<Emitter> LocalScope(this, VD); if (VarT) { if (!this->visit(Init)) return false; - return this->emitInitGlobal(*VarT, *GlobalIndex, VD); + return this->emitInitGlobal(*VarT, GlobalIndex, VD); } - return this->visitGlobalInitializer(Init, *GlobalIndex); + return this->visitGlobalInitializer(Init, GlobalIndex); + }; + + // We've already seen and initialized this global. + if (std::optional<unsigned> GlobalIndex = P.getGlobal(VD)) { + if (P.getPtrGlobal(*GlobalIndex).isInitialized()) + return true; + + // The previous attempt at initialization might've been unsuccessful, + // so let's try this one. + return Init && initGlobal(*GlobalIndex); } - return true; + + std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init); + + if (!GlobalIndex) + return false; + + return !Init || initGlobal(*GlobalIndex); } else { VariableScope<Emitter> LocalScope(this); if (VarT) { diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index e5e2c932f500b8..2607e074325167 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -56,22 +56,65 @@ static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) { return true; } +static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, + const ValueDecl *VD) { + const SourceInfo &E = S.Current->getSource(OpPC); + S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD; + S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); +} + +static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, + const ValueDecl *VD); +static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, + const ValueDecl *D) { + const SourceInfo &E = S.Current->getSource(OpPC); + + if (isa<ParmVarDecl>(D)) { + if (S.getLangOpts().CPlusPlus11) { + S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D; + S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange(); + } else { + S.FFDiag(E); + } + } else if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (!VD->getType().isConstQualified()) { + diagnoseNonConstVariable(S, OpPC, VD); + return false; + } + + // const, but no initializer. + if (!VD->getAnyInitializer()) { + diagnoseMissingInitializer(S, OpPC, VD); + return false; + } + } + return false; +} + static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD) { if (!S.getLangOpts().CPlusPlus) return; const SourceInfo &Loc = S.Current->getSource(OpPC); + if (const auto *VarD = dyn_cast<VarDecl>(VD); + VarD && VarD->getType().isConstQualified() && + !VarD->getAnyInitializer()) { + diagnoseMissingInitializer(S, OpPC, VD); + return; + } - if (VD->getType()->isIntegralOrEnumerationType()) + 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); + return; + } + + 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); } @@ -202,6 +245,9 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!Ptr.isExtern()) return true; + if (Ptr.isInitialized()) + return true; + if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) { const auto *VD = Ptr.getDeclDesc()->asValueDecl(); diagnoseNonConstVariable(S, OpPC, VD); @@ -369,9 +415,15 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (const auto *VD = Ptr.getDeclDesc()->asVarDecl(); VD && VD->hasGlobalStorage()) { const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; - S.Note(VD->getLocation(), diag::note_declared_at); + if (VD->getAnyInitializer()) { + S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; + S.Note(VD->getLocation(), diag::note_declared_at); + } else { + diagnoseMissingInitializer(S, OpPC, VD); + } + return false; } + if (!S.checkingPotentialConstantExpression()) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit) << AK << /*uninitialized=*/true << S.Current->getRange(OpPC); @@ -598,33 +650,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, return true; } -static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, - const ValueDecl *D) { - const SourceInfo &E = S.Current->getSource(OpPC); - - if (isa<ParmVarDecl>(D)) { - if (S.getLangOpts().CPlusPlus11) { - S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D; - S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange(); - } else { - S.FFDiag(E); - } - } else if (const auto *VD = dyn_cast<VarDecl>(D)) { - if (!VD->getType().isConstQualified()) { - diagnoseNonConstVariable(S, OpPC, VD); - return false; - } - - // const, but no initializer. - if (!VD->getAnyInitializer()) { - S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD; - S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); - return false; - } - } - return false; -} - /// We aleady know the given DeclRefExpr is invalid for some reason, /// now figure out why and print appropriate diagnostics. bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) { diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 82367164743fc3..e6f22e79451e97 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -177,7 +177,7 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD, bool IsStatic, IsExtern; if (const auto *Var = dyn_cast<VarDecl>(VD)) { IsStatic = Context::shouldBeGloballyIndexed(VD); - IsExtern = !Var->getAnyInitializer(); + IsExtern = Var->hasExternalStorage(); } else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl>(VD)) { IsStatic = true; IsExtern = false; diff --git a/clang/test/AST/Interp/cxx23.cpp b/clang/test/AST/Interp/cxx23.cpp index 042e29613aa753..f0325eef6d87cf 100644 --- a/clang/test/AST/Interp/cxx23.cpp +++ b/clang/test/AST/Interp/cxx23.cpp @@ -5,23 +5,18 @@ /// FIXME: The new interpreter is missing all the 'control flows through...' diagnostics. -constexpr int f(int n) { // ref20-error {{constexpr function never produces a constant expression}} \ - // expected20-error {{constexpr function never produces a constant expression}} +constexpr int f(int n) { // ref20-error {{constexpr function never produces a constant expression}} static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \ // ref20-warning {{is a C++23 extension}} \ - // expected20-warning {{is a C++23 extension}} \ - // expected20-note {{declared here}} \ + // expected20-warning {{is a C++23 extension}} - return m; // expected20-note {{initializer of 'm' is not a constant expression}} + return m; } -constexpr int g(int n) { // ref20-error {{constexpr function never produces a constant expression}} \ - // expected20-error {{constexpr function never produces a constant expression}} +constexpr int g(int n) { // ref20-error {{constexpr function never produces a constant expression}} thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \ // ref20-warning {{is a C++23 extension}} \ - // expected20-warning {{is a C++23 extension}} \ - // expected20-note {{declared here}} - return m; // expected20-note {{initializer of 'm' is not a constant expression}} - + // expected20-warning {{is a C++23 extension}} + return m; } constexpr int c_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \ diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 0f76e0cfe99277..f251497ed70182 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1,11 +1,11 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify=expected,both %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=expected,both %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -triple i686 -verify=expected,both %s // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,both %s -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple i686 -verify=expected,both %s -// RUN: %clang_cc1 -verify=ref,both %s // RUN: %clang_cc1 -verify=ref,both -std=c++14 %s +// RUN: %clang_cc1 -verify=ref,both -std=c++17 %s +// RUN: %clang_cc1 -verify=ref,both -std=c++17 -triple i686 %s // RUN: %clang_cc1 -verify=ref,both -std=c++20 %s -// RUN: %clang_cc1 -verify=ref,both -triple i686 %s /// Used to crash. struct Empty {}; @@ -1285,3 +1285,27 @@ namespace { } } #endif + +namespace pr18633 { + struct A1 { + static const int sz; + static const int sz2; + }; + const int A1::sz2 = 11; + template<typename T> + void func () { + int arr[A1::sz]; + // both-warning@-1 {{variable length arrays in C++ are a Clang extension}} + // both-note@-2 {{initializer of 'sz' is unknown}} + // both-note@-9 {{declared here}} + } + template<typename T> + void func2 () { + int arr[A1::sz2]; + } + const int A1::sz = 12; + void func2() { + func<int>(); + func2<int>(); + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits