Skip to content

Conversation

@tbaederr
Copy link
Contributor

@tbaederr tbaederr commented Aug 8, 2024

createGlobal fails e.g. if the type isn't complete.

createGlobal fails e.g. if the type isn't complete.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 8, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 8, 2024

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

createGlobal fails e.g. if the type isn't complete.


Full diff: https://github.com/llvm/llvm-project/pull/102464.diff

3 Files Affected:

  • (modified) clang/lib/AST/Interp/Compiler.cpp (+11-7)
  • (modified) clang/lib/AST/Interp/Compiler.h (+6-5)
  • (modified) clang/test/AST/Interp/records.cpp (+10)
diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 11fe2acf2d7b9..165fabbfe3d73 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -3617,7 +3617,7 @@ VarCreationState Compiler<Emitter>::visitDecl(const VarDecl *VD) {
 
   auto R = this->visitVarDecl(VD, /*Toplevel=*/true);
 
-  if (R.notCreated())
+  if (R.notCreated() || R.dummyCreated())
     return R;
 
   if (R)
@@ -3709,7 +3709,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, bool Topleve
   // This case is EvalEmitter-only. If we won't create any instructions for the
   // initializer anyway, don't bother creating the variable in the first place.
   if (!this->isActive())
-    return VarCreationState::NotCreated();
+    return VarCreationState::NotCreated;
 
   const Expr *Init = VD->getInit();
   std::optional<PrimType> VarT = classify(VD->getType());
@@ -3759,12 +3759,16 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, bool Topleve
       return Init && checkDecl() && initGlobal(*GlobalIndex);
     }
 
-    std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);
+    if (std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init))
+      return !Init || (checkDecl() && initGlobal(*GlobalIndex));
 
-    if (!GlobalIndex)
-      return false;
+    if (std::optional<unsigned> I = P.getOrCreateDummy(VD)) {
+      if (!this->emitGetPtrGlobal(*I, VD))
+        return false;
+      return VarCreationState::DummyCreated;
+    }
 
-    return !Init || (checkDecl() && initGlobal(*GlobalIndex));
+    return false;
   } else {
     InitLinkScope<Emitter> ILS(this, InitLink::Decl(VD));
 
@@ -5240,7 +5244,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
   auto revisit = [&](const VarDecl *VD) -> bool {
     auto VarState = this->visitDecl(VD);
 
-    if (VarState.notCreated())
+    if (VarState.notCreated() || VarState.dummyCreated())
       return true;
     if (!VarState)
       return false;
diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h
index 244a600d061f4..4888e499bd6d4 100644
--- a/clang/lib/AST/Interp/Compiler.h
+++ b/clang/lib/AST/Interp/Compiler.h
@@ -89,13 +89,14 @@ struct InitLink {
 /// State encapsulating if a the variable creation has been successful,
 /// unsuccessful, or no variable has been created at all.
 struct VarCreationState {
-  std::optional<bool> S = std::nullopt;
+  enum SS { Failure = 0, Success = 1, NotCreated, DummyCreated } S;
   VarCreationState() = default;
-  VarCreationState(bool b) : S(b) {}
-  static VarCreationState NotCreated() { return VarCreationState(); }
+  VarCreationState(SS b) : S(b) {}
+  VarCreationState(bool b) : S(b ? Success : Failure) {}
 
-  operator bool() const { return S && *S; }
-  bool notCreated() const { return !S; }
+  operator bool() const { return S == Success; }
+  bool notCreated() const { return S == NotCreated; }
+  bool dummyCreated() const { return S == DummyCreated; }
 };
 
 /// Compilation context for expressions.
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 479c0487fecae..48c07e2953ebf 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -1576,3 +1576,13 @@ namespace ctorOverrider {
   constexpr Covariant1 cb;
 }
 #endif
+
+namespace IncompleteStaticStructMember {
+  struct Foo;
+  struct Bar {
+    static const Foo x;
+    static const Foo y;
+  };
+  static_assert(&Bar::x != nullptr, ""); // both-warning {{always true}}
+  static_assert(&Bar::x != &Bar::y, "");
+}

@MitalAshok
Copy link
Contributor

struct Foo;
struct Bar {
  static const Foo x;
  static const Foo y;
};
static_assert(&Bar::x != nullptr, ""); // both-warning {{always true}}
static_assert(&Bar::x != &Bar::y, "");
constexpr const Foo* xp = &Bar::x;
struct Foo {};
static_assert(xp == &Bar::x);  // This fails with -fexperimental-new-constant-interpreter

@tbaederr tbaederr closed this Aug 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants