Skip to content

Commit

Permalink
[clang][Interp] Diagnose uninitialized global variables explicitly
Browse files Browse the repository at this point in the history
There used to be some diagnostic differences between the new
interpreter and the old one.
  • Loading branch information
tbaederr committed Feb 20, 2024
1 parent dfb70c3 commit 9563746
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 23 deletions.
4 changes: 4 additions & 0 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
29 changes: 11 additions & 18 deletions clang/test/AST/Interp/cxx17.cpp
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -81,22 +81,15 @@ constexpr int b() {
}
static_assert(b() == 11);

/// The diagnostics between the two interpreters are different here.
/// The diagnostics between the two interpreters used to be different 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}}
10 changes: 5 additions & 5 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 9563746

Please sign in to comment.