[clang] 9563746 - [clang][Interp] Diagnose uninitialized global variables explicitly
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 20 05:20:28 PST 2024
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:
More information about the cfe-commits
mailing list