Skip to content

[clang][Interp] Fall back to dummy pointers if createGlobal() fails #102464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

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

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