[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