Author: Timm Bäder Date: 2024-02-20T14:20:17+01:00 New Revision: 9563746d358c68c0c4a6242fa20bc21fdf632dfe
URL: https://github.com/llvm/llvm-project/commit/9563746d358c68c0c4a6242fa20bc21fdf632dfe DIFF: https://github.com/llvm/llvm-project/commit/9563746d358c68c0c4a6242fa20bc21fdf632dfe.diff LOG: [clang][Interp] Diagnose uninitialized global variables explicitly There used to be some diagnostic differences between the new interpreter and the old one. Added: Modified: clang/lib/AST/Interp/Descriptor.h clang/lib/AST/Interp/Interp.cpp clang/test/AST/Interp/cxx17.cpp clang/test/AST/Interp/records.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h index 6a53205af59926..ac8707a521e194 100644 --- a/clang/lib/AST/Interp/Descriptor.h +++ b/clang/lib/AST/Interp/Descriptor.h @@ -165,6 +165,10 @@ struct Descriptor final { return dyn_cast_if_present<ValueDecl>(asDecl()); } + const VarDecl *asVarDecl() const { + return dyn_cast_if_present<VarDecl>(asDecl()); + } + const FieldDecl *asFieldDecl() const { return dyn_cast_if_present<FieldDecl>(asDecl()); } diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 51434d65e2f53b..1a48b8bddced02 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -357,10 +357,18 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK) { + assert(Ptr.isLive()); + if (Ptr.isInitialized()) return true; if (!S.checkingPotentialConstantExpression()) { + 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); + } S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit) << AK << /*uninitialized=*/true << S.Current->getRange(OpPC); } diff --git a/clang/test/AST/Interp/cxx17.cpp b/clang/test/AST/Interp/cxx17.cpp index 76d985eb22e178..5e38d1a5887007 100644 --- a/clang/test/AST/Interp/cxx17.cpp +++ b/clang/test/AST/Interp/cxx17.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify %s -// RUN: %clang_cc1 -std=c++17 -verify=ref %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=expected,both %s +// RUN: %clang_cc1 -std=c++17 -verify=ref,both %s struct F { int a; int b;}; constexpr F getF() { @@ -81,22 +81,15 @@ constexpr int b() { } static_assert(b() == 11); -/// The diagnostics between the two interpreters are diff erent here. +/// The diagnostics between the two interpreters used to be diff erent here. struct S { int a; }; -constexpr S getS() { // expected-error {{constexpr function never produces a constant expression}} \\ - // ref-error {{constexpr function never produces a constant expression}} - (void)(1/0); // expected-note 2{{division by zero}} \ - // expected-warning {{division by zero}} \ - // ref-note 2{{division by zero}} \ - // ref-warning {{division by zero}} +constexpr S getS() { // both-error {{constexpr function never produces a constant expression}} + (void)(1/0); // both-note 2{{division by zero}} \ + // both-warning {{division by zero}} return S{12}; } -constexpr S s = getS(); // expected-error {{must be initialized by a constant expression}} \ - // expected-note {{in call to 'getS()'}} \ - // ref-error {{must be initialized by a constant expression}} \\ - // ref-note {{in call to 'getS()'}} \ - // ref-note {{declared here}} -static_assert(s.a == 12, ""); // expected-error {{not an integral constant expression}} \ - // expected-note {{read of uninitialized object}} \ - // ref-error {{not an integral constant expression}} \ - // ref-note {{initializer of 's' is not a constant expression}} +constexpr S s = getS(); // both-error {{must be initialized by a constant expression}} \ + // both-note {{in call to 'getS()'}} \ + // both-note {{declared here}} +static_assert(s.a == 12, ""); // both-error {{not an integral constant expression}} \ + // both-note {{initializer of 's' is not a constant expression}} diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 7cc5987e0a958f..7ddc56c9b5dfc4 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -420,11 +420,10 @@ namespace DeriveFailures { constexpr Derived D(12); // both-error {{must be initialized by a constant expression}} \ // both-note {{in call to 'Derived(12)'}} \ - // ref-note {{declared here}} + // both-note {{declared here}} static_assert(D.Val == 0, ""); // both-error {{not an integral constant expression}} \ - // ref-note {{initializer of 'D' is not a constant expression}} \ - // expected-note {{read of uninitialized object}} + // both-note {{initializer of 'D' is not a constant expression}} #endif struct AnotherBase { @@ -478,10 +477,11 @@ namespace ConditionalInit { namespace DeclRefs { struct A{ int m; const int &f = m; }; // expected-note {{implicit use of 'this'}} - constexpr A a{10}; // expected-error {{must be initialized by a constant expression}} + constexpr A a{10}; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{declared here}} static_assert(a.m == 10, ""); static_assert(a.f == 10, ""); // expected-error {{not an integral constant expression}} \ - // expected-note {{read of uninitialized object}} + // expected-note {{initializer of 'a' is not a constant expression}} class Foo { public: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits