Skip to content

Conversation

@hnrklssn
Copy link
Member

Original commit in f2e9f88, fix triggered assert in f9272dd360b93f85b7fea6acb82d631f074200d2

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules labels Jun 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 24, 2025

@llvm/pr-subscribers-clang-modules

@llvm/pr-subscribers-clang

Author: Henrik G. Olsson (hnrklssn)

Changes

Original commit in f2e9f88, fix triggered assert in f9272dd360b93f85b7fea6acb82d631f074200d2


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

12 Files Affected:

  • (modified) clang/include/clang/AST/Decl.h (+5)
  • (modified) clang/include/clang/AST/ExternalASTSource.h (+16)
  • (modified) clang/include/clang/Sema/MultiplexExternalSemaSource.h (+2)
  • (modified) clang/include/clang/Serialization/ASTReader.h (+8)
  • (modified) clang/lib/AST/ASTContext.cpp (+1-3)
  • (modified) clang/lib/AST/Decl.cpp (+24)
  • (modified) clang/lib/AST/ExprConstant.cpp (+3)
  • (modified) clang/lib/Sema/MultiplexExternalSemaSource.cpp (+8)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+4)
  • (modified) clang/lib/Serialization/ASTReaderDecl.cpp (+3)
  • (modified) clang/lib/Serialization/ASTWriterDecl.cpp (+8-6)
  • (added) clang/test/Modules/var-init-side-effects.cpp (+37)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 58209f4601422..0da940883b6f5 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1352,6 +1352,11 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
     return const_cast<VarDecl *>(this)->getInitializingDeclaration();
   }
 
+  /// Checks whether this declaration has an initializer with side effects,
+  /// without triggering deserialization if the initializer is not yet
+  /// deserialized.
+  bool hasInitWithSideEffects() const;
+
   /// Determine whether this variable's value might be usable in a
   /// constant expression, according to the relevant language standard.
   /// This only checks properties of the declaration, and does not check
diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h
index f45e3af7602c1..e91d5132da10f 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -51,6 +51,7 @@ class RecordDecl;
 class Selector;
 class Stmt;
 class TagDecl;
+class VarDecl;
 
 /// Abstract interface for external sources of AST nodes.
 ///
@@ -195,6 +196,10 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
   /// module.
   virtual bool wasThisDeclarationADefinition(const FunctionDecl *FD);
 
+  virtual bool hasInitializerWithSideEffects(const VarDecl *VD) const {
+    return false;
+  }
+
   /// Finds all declarations lexically contained within the given
   /// DeclContext, after applying an optional filter predicate.
   ///
@@ -429,6 +434,17 @@ struct LazyOffsetPtr {
     return GetPtr();
   }
 
+  /// Retrieve the pointer to the AST node that this lazy pointer points to,
+  /// if it can be done without triggering deserialization.
+  ///
+  /// \returns a pointer to the AST node, or null if not yet deserialized.
+  T *getWithoutDeserializing() const {
+    if (isOffset()) {
+      return nullptr;
+    }
+    return GetPtr();
+  }
+
   /// Retrieve the address of the AST node pointer. Deserializes the pointee if
   /// necessary.
   T **getAddressOfPointer(ExternalASTSource *Source) const {
diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
index 391c2177d75ec..7c66c26a17a13 100644
--- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -94,6 +94,8 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
 
   bool wasThisDeclarationADefinition(const FunctionDecl *FD) override;
 
+  bool hasInitializerWithSideEffects(const VarDecl *VD) const override;
+
   /// Find all declarations with the given name in the
   /// given context.
   bool FindExternalVisibleDeclsByName(const DeclContext *DC,
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index be1c6e0817593..7a4b7d21bb20e 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -1455,6 +1455,12 @@ class ASTReader
     const StringRef &operator*() && = delete;
   };
 
+  /// VarDecls with initializers containing side effects must be emitted,
+  /// but DeclMustBeEmitted is not allowed to deserialize the intializer.
+  /// FIXME: Lower memory usage by removing VarDecls once the initializer
+  /// is deserialized.
+  llvm::SmallPtrSet<Decl *, 16> InitSideEffectVars;
+
 public:
   /// Get the buffer for resolving paths.
   SmallString<0> &getPathBuf() { return PathBuf; }
@@ -2406,6 +2412,8 @@ class ASTReader
 
   bool wasThisDeclarationADefinition(const FunctionDecl *FD) override;
 
+  bool hasInitializerWithSideEffects(const VarDecl *VD) const override;
+
   /// Retrieve a selector from the given module with its local ID
   /// number.
   Selector getLocalSelector(ModuleFile &M, unsigned LocalID);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index e851e8c3d8143..eba3c3de3d092 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -13110,9 +13110,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
     return true;
 
   // Variables that have initialization with side-effects are required.
-  if (VD->getInit() && VD->getInit()->HasSideEffects(*this) &&
-      // We can get a value-dependent initializer during error recovery.
-      (VD->getInit()->isValueDependent() || !VD->evaluateValue()))
+  if (VD->hasInitWithSideEffects())
     return true;
 
   // Likewise, variables with tuple-like bindings are required if their
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 2f01c715ae4ba..35c41859595da 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2441,6 +2441,30 @@ VarDecl *VarDecl::getInitializingDeclaration() {
   return Def;
 }
 
+bool VarDecl::hasInitWithSideEffects() const {
+  if (!hasInit())
+    return false;
+
+  // Check if we can get the initializer without deserializing
+  const Expr *E = nullptr;
+  if (auto *S = dyn_cast<Stmt *>(Init)) {
+    E = cast<Expr>(S);
+  } else {
+    E = cast_or_null<Expr>(getEvaluatedStmt()->Value.getWithoutDeserializing());
+  }
+
+  if (E)
+    return E->HasSideEffects(getASTContext()) &&
+           // We can get a value-dependent initializer during error recovery.
+           (E->isValueDependent() || !evaluateValue());
+
+  assert(getEvaluatedStmt()->Value.isOffset());
+  // ASTReader tracks this without having to deserialize the initializer
+  if (auto Source = getASTContext().getExternalSource())
+    return Source->hasInitializerWithSideEffects(this);
+  return false;
+}
+
 bool VarDecl::isOutOfLine() const {
   if (Decl::isOutOfLine())
     return true;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 18ad326942273..c19e50c9aacb2 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16719,6 +16719,9 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
                             const Expr *E, bool AllowNonLiteralTypes) {
   assert(!E->isValueDependent());
 
+  if (E->getType().isNull())
+    return false;
+
   if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E, &This))
     return false;
 
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index fbfb242598c24..9f19f13592e86 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -115,6 +115,14 @@ bool MultiplexExternalSemaSource::wasThisDeclarationADefinition(
   return false;
 }
 
+bool MultiplexExternalSemaSource::hasInitializerWithSideEffects(
+    const VarDecl *VD) const {
+  for (const auto &S : Sources)
+    if (S->hasInitializerWithSideEffects(VD))
+      return true;
+  return false;
+}
+
 bool MultiplexExternalSemaSource::FindExternalVisibleDeclsByName(
     const DeclContext *DC, DeclarationName Name,
     const DeclContext *OriginalDC) {
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index a3fbc3d25acab..6f082fe840b4c 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9722,6 +9722,10 @@ bool ASTReader::wasThisDeclarationADefinition(const FunctionDecl *FD) {
   return ThisDeclarationWasADefinitionSet.contains(FD);
 }
 
+bool ASTReader::hasInitializerWithSideEffects(const VarDecl *VD) const {
+  return InitSideEffectVars.count(VD);
+}
+
 Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
   return DecodeSelector(getGlobalSelectorID(M, LocalID));
 }
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 7f7882654b9d1..0ffd78424be0d 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1628,6 +1628,9 @@ RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
     VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope =
         VarDeclBits.getNextBit();
 
+    if (VarDeclBits.getNextBit())
+      Reader.InitSideEffectVars.insert(VD);
+
     VD->NonParmVarDeclBits.EscapingByref = VarDeclBits.getNextBit();
     HasDeducedType = VarDeclBits.getNextBit();
     VD->NonParmVarDeclBits.ImplicitParamKind =
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 2d93832a9ac31..2e390dbe79ec6 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1306,6 +1306,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
     VarDeclBits.addBit(D->isConstexpr());
     VarDeclBits.addBit(D->isInitCapture());
     VarDeclBits.addBit(D->isPreviousDeclInSameBlockScope());
+    VarDeclBits.addBit(D->hasInitWithSideEffects());
 
     VarDeclBits.addBit(D->isEscapingByref());
     HasDeducedType = D->getType()->getContainedDeducedType();
@@ -1355,10 +1356,11 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
       !D->hasExtInfo() && D->getFirstDecl() == D->getMostRecentDecl() &&
       D->getKind() == Decl::Var && !D->isInline() && !D->isConstexpr() &&
       !D->isInitCapture() && !D->isPreviousDeclInSameBlockScope() &&
-      !D->isEscapingByref() && !HasDeducedType &&
-      D->getStorageDuration() != SD_Static && !D->getDescribedVarTemplate() &&
-      !D->getMemberSpecializationInfo() && !D->isObjCForDecl() &&
-      !isa<ImplicitParamDecl>(D) && !D->isEscapingByref())
+      !D->hasInitWithSideEffects() && !D->isEscapingByref() &&
+      !HasDeducedType && D->getStorageDuration() != SD_Static &&
+      !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() &&
+      !D->isObjCForDecl() && !isa<ImplicitParamDecl>(D) &&
+      !D->isEscapingByref())
     AbbrevToUse = Writer.getDeclVarAbbrev();
 
   Code = serialization::DECL_VAR;
@@ -2731,12 +2733,12 @@ void ASTWriter::WriteDeclAbbrevs() {
   // VarDecl
   Abv->Add(BitCodeAbbrevOp(
       BitCodeAbbrevOp::Fixed,
-      21)); // Packed Var Decl bits:  Linkage, ModulesCodegen,
+      22)); // Packed Var Decl bits:  Linkage, ModulesCodegen,
             // SClass, TSCSpec, InitStyle,
             // isARCPseudoStrong, IsThisDeclarationADemotedDefinition,
             // isExceptionVariable, isNRVOVariable, isCXXForRangeDecl,
             // isInline, isInlineSpecified, isConstexpr,
-            // isInitCapture, isPrevDeclInSameScope,
+            // isInitCapture, isPrevDeclInSameScope, hasInitWithSideEffects,
             // EscapingByref, HasDeducedType, ImplicitParamKind, isObjCForDecl
   Abv->Add(BitCodeAbbrevOp(0));                         // VarKind (local enum)
   // Type Source Info
diff --git a/clang/test/Modules/var-init-side-effects.cpp b/clang/test/Modules/var-init-side-effects.cpp
new file mode 100644
index 0000000000000..438a9eb204275
--- /dev/null
+++ b/clang/test/Modules/var-init-side-effects.cpp
@@ -0,0 +1,37 @@
+// Tests referencing variable with initializer containing side effect across module boundary
+//
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/Foo.cppm \
+// RUN: -o %t/Foo.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface \
+// RUN: -fmodule-file=Foo=%t/Foo.pcm \
+// RUN: %t/Bar.cppm \
+// RUN: -o %t/Bar.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-obj \
+// RUN: -main-file-name Bar.cppm \
+// RUN: -fmodule-file=Foo=%t/Foo.pcm \
+// RUN: -x pcm %t/Bar.pcm \
+// RUN: -o %t/Bar.o
+
+//--- Foo.cppm
+export module Foo;
+
+export {
+class S {};
+
+inline S s = S{};
+}
+
+//--- Bar.cppm
+export module Bar;
+import Foo;
+
+S bar() {
+  return s;
+}
+

Copy link
Member

@ChuanqiXu9 ChuanqiXu9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between this one and the previous PR?

@hnrklssn
Copy link
Member Author

What is the difference between this one and the previous PR?

The second commit, where I prevent constant evaluation if the expression type is null

Normally expressions passed to EvaluateInPlace have a type, but not when
a VarDecl initializer is evaluated before the untyped ParenListExpr is
replaced with a CXXConstructExpr. This can happen in LLDB. In these
cases consteval fails.
@hnrklssn hnrklssn force-pushed the reland-serialize-side-effects branch from f9272dd to e8db4a4 Compare June 24, 2025 03:18
@hnrklssn hnrklssn merged commit 37eb465 into llvm:main Jun 24, 2025
5 of 7 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Jun 24, 2025

LLVM Buildbot has detected a new failure on builder clang-m68k-linux-cross running on suse-gary-m68k-cross while building clang at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/27/builds/12004

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
...
In file included from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Parse/Parser.h:20,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Analysis/MacroExpansionContextTest.cpp:23:
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Sema/Sema.h:839:7: warning: ‘clang::Sema’ declared with greater visibility than the type of its field ‘clang::Sema::UnusedFileScopedDecls’ [-Wattributes]
  839 | class Sema final : public SemaBase {
      |       ^~~~
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Sema/Sema.h:839:7: warning: ‘clang::Sema’ declared with greater visibility than the type of its field ‘clang::Sema::TentativeDefinitions’ [-Wattributes]
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Sema/Sema.h:839:7: warning: ‘clang::Sema’ declared with greater visibility than the type of its field ‘clang::Sema::ExtVectorDecls’ [-Wattributes]
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Sema/Sema.h:839:7: warning: ‘clang::Sema’ declared with greater visibility than the type of its field ‘clang::Sema::DelegatingCtorDecls’ [-Wattributes]
[123/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/AnalyzerOptionsTest.cpp.o
[124/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o
FAILED: tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o 
/usr/bin/c++ -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/unittests -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Tooling -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googletest/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googlemock/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wno-maybe-uninitialized -Wno-nonnull -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wno-misleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -O3 -DNDEBUG -std=c++17  -Wno-variadic-macros -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -Wno-suggest-override -MD -MT tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o -MF tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o.d -o tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o -c /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Analysis/IntervalPartitionTest.cpp
c++: fatal error: Killed signal terminated program cc1plus
compilation terminated.
[125/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/APSIntTypeTest.cpp.o
[126/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/ASTOpsTest.cpp.o
[127/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/CFGMatchSwitchTest.cpp.o
[128/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/DeterminismTest.cpp.o
[129/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/LoggerTest.cpp.o
[130/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/MatchSwitchTest.cpp.o
[131/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/BlockEntranceCallbackTest.cpp.o
[132/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/CallEventTest.cpp.o
[133/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/MapLatticeTest.cpp.o
[134/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp.o
[135/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp.o
[136/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/CachedConstAccessorsLatticeTest.cpp.o
[137/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/ExprEngineVisitTest.cpp.o
[138/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/ConflictingEvalCallsTest.cpp.o
[139/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/TransferBranchTest.cpp.o
[140/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/SimplifyConstraintsTest.cpp.o
[141/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/SingleVarConstantPropagationTest.cpp.o
[142/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/RecordOpsTest.cpp.o
[143/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/TestingSupport.cpp.o
[144/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/DebugSupportTest.cpp.o
[145/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/TestingSupportTest.cpp.o
[146/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp.o
[147/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/ExprMutationAnalyzerTest.cpp.o
[148/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/SignAnalysisTest.cpp.o
[149/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp.o
[150/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/BugReportInterestingnessTest.cpp.o
[151/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/CallDescriptionTest.cpp.o
[152/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/WatchedLiteralsSolverTest.cpp.o
[153/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp.o
[154/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp.o
[155/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/StaticAnalyzer/IsCLibraryFunctionTest.cpp.o
[156/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp.o
[157/377] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/TransferTest.cpp.o
ninja: build stopped: subcommand failed.

DrSergei pushed a commit to DrSergei/llvm-project that referenced this pull request Jun 24, 2025
…fects" (llvm#145447)

This reverts commit 329ae86 and adds an early exit for EvaluateInPlace when the expression's type is null.
anthonyhatran pushed a commit to anthonyhatran/llvm-project that referenced this pull request Jun 26, 2025
…fects" (llvm#145447)

This reverts commit 329ae86 and adds an early exit for EvaluateInPlace when the expression's type is null.
@bgra8
Copy link
Contributor

bgra8 commented Jul 4, 2025

@hnrklssn we (at google) have bisected a clang crash at the original commit (319a51a) that also reproduces at this revision.

Here's the stack trace:

assert.h assertion failed at llvm-project/llvm/include/llvm/Support/Casting.h:566 in decltype(auto) llvm::cast(const From &) [To = clang::RecordType, From = clang::QualType]: isa<To>(Val) && "cast<Ty>() argument of incompatible type!"
*** Check failure stack trace: ***
    @     0x55b57e120f04  absl::log_internal::LogMessage::SendToLog()
    @     0x55b57e120ec7  absl::log_internal::LogMessage::Flush()
    @     0x55b57e349204  __assert_fail
    @     0x55b57a572ad0  CheckEvaluationResult()
    @     0x55b57a5353a5  clang::Expr::EvaluateAsInitializer()
    @     0x55b57a44eb32  clang::VarDecl::evaluateValueImpl()
    @     0x55b57a44e07a  clang::VarDecl::evaluateValue()
    @     0x55b57a44df78  clang::VarDecl::hasInitWithSideEffects()
    @     0x55b579595839  clang::ASTDeclWriter::VisitVarDecl()
    @     0x55b57958e996  clang::ASTDeclWriter::Visit()
    @     0x55b5795a18bc  clang::ASTWriter::WriteDecl()
    @     0x55b579551725  clang::ASTWriter::WriteDeclAndTypes()
    @     0x55b57954b42b  clang::ASTWriter::WriteASTCore()
    @     0x55b57954a131  clang::ASTWriter::WriteAST()
    @     0x55b5795bb1e0  clang::PCHGenerator::HandleTranslationUnit()
    @     0x55b579127cfd  clang::MultiplexConsumer::HandleTranslationUnit()
    @     0x55b57933a948  clang::ParseAST()
    @     0x55b57906e34a  clang::FrontendAction::Execute()
    @     0x55b578fe125d  clang::CompilerInstance::ExecuteAction()
    @     0x55b57842586b  clang::ExecuteCompilerInvocation()
    @     0x55b578419218  cc1_main()
    @     0x55b578416334  ExecuteCC1Tool()
    @     0x55b579197a3e  llvm::function_ref<>::callback_fn<>()
    @     0x55b57df95c9c  llvm::CrashRecoveryContext::RunSafely()
    @     0x55b579196f24  clang::driver::CC1Command::Execute()
    @     0x55b579157615  clang::driver::Compilation::ExecuteCommand()
    @     0x55b5791578af  clang::driver::Compilation::ExecuteJobs()
    @     0x55b579173200  clang::driver::Driver::ExecuteCompilation()
    @     0x55b57841593d  clang_main()
    @     0x55b578413cf4  main
    @     0x7fc1572933d4  __libc_start_main
    @     0x55b578413c2a  _start

Can you please take a look?

@hnrklssn
Copy link
Member Author

hnrklssn commented Jul 4, 2025

@hnrklssn we (at google) have bisected a clang crash at the original commit (319a51a) that also reproduces at this revision.

Here's the stack trace:


assert.h assertion failed at llvm-project/llvm/include/llvm/Support/Casting.h:566 in decltype(auto) llvm::cast(const From &) [To = clang::RecordType, From = clang::QualType]: isa<To>(Val) && "cast<Ty>() argument of incompatible type!"

*** Check failure stack trace: ***

    @     0x55b57e120f04  absl::log_internal::LogMessage::SendToLog()

    @     0x55b57e120ec7  absl::log_internal::LogMessage::Flush()

    @     0x55b57e349204  __assert_fail

    @     0x55b57a572ad0  CheckEvaluationResult()

    @     0x55b57a5353a5  clang::Expr::EvaluateAsInitializer()

    @     0x55b57a44eb32  clang::VarDecl::evaluateValueImpl()

    @     0x55b57a44e07a  clang::VarDecl::evaluateValue()

    @     0x55b57a44df78  clang::VarDecl::hasInitWithSideEffects()

    @     0x55b579595839  clang::ASTDeclWriter::VisitVarDecl()

    @     0x55b57958e996  clang::ASTDeclWriter::Visit()

    @     0x55b5795a18bc  clang::ASTWriter::WriteDecl()

    @     0x55b579551725  clang::ASTWriter::WriteDeclAndTypes()

    @     0x55b57954b42b  clang::ASTWriter::WriteASTCore()

    @     0x55b57954a131  clang::ASTWriter::WriteAST()

    @     0x55b5795bb1e0  clang::PCHGenerator::HandleTranslationUnit()

    @     0x55b579127cfd  clang::MultiplexConsumer::HandleTranslationUnit()

    @     0x55b57933a948  clang::ParseAST()

    @     0x55b57906e34a  clang::FrontendAction::Execute()

    @     0x55b578fe125d  clang::CompilerInstance::ExecuteAction()

    @     0x55b57842586b  clang::ExecuteCompilerInvocation()

    @     0x55b578419218  cc1_main()

    @     0x55b578416334  ExecuteCC1Tool()

    @     0x55b579197a3e  llvm::function_ref<>::callback_fn<>()

    @     0x55b57df95c9c  llvm::CrashRecoveryContext::RunSafely()

    @     0x55b579196f24  clang::driver::CC1Command::Execute()

    @     0x55b579157615  clang::driver::Compilation::ExecuteCommand()

    @     0x55b5791578af  clang::driver::Compilation::ExecuteJobs()

    @     0x55b579173200  clang::driver::Driver::ExecuteCompilation()

    @     0x55b57841593d  clang_main()

    @     0x55b578413cf4  main

    @     0x7fc1572933d4  __libc_start_main

    @     0x55b578413c2a  _start

Can you please take a look?

Is it fixed by #146468?

@bgra8
Copy link
Contributor

bgra8 commented Jul 4, 2025

Is it fixed by #146468?

I patched #146468 after this change, rebuilt the compiler and reproduced the same crash. So I guess that patch does not fix the issue I see here. Does #146468 depend on some other change?

The assertion looks similar:

assert.h assertion failed at llvm-project/llvm/include/llvm/Support/Casting.h:566 in decltype(auto) llvm::cast(const From &) [To = clang::RecordType, From = clang::QualType]: isa<To>(Val) && "cast<Ty>() argument of incompatible type!"
*** Check failure stack trace: ***
    @     0x564b4bf20f04  absl::log_internal::LogMessage::SendToLog()
    @     0x564b4bf20ec7  absl::log_internal::LogMessage::Flush()
    @     0x564b4c149204  __assert_fail
    @     0x564b48372ad0  CheckEvaluationResult()
    @     0x564b483353a5  clang::Expr::EvaluateAsInitializer()
    @     0x564b4824eb32  clang::VarDecl::evaluateValueImpl()
    @     0x564b4824e07a  clang::VarDecl::evaluateValue()
    @     0x564b4824df78  clang::VarDecl::hasInitWithSideEffects()
    @     0x564b47395839  clang::ASTDeclWriter::VisitVarDecl()
    @     0x564b4738e996  clang::ASTDeclWriter::Visit()
    @     0x564b473a18bc  clang::ASTWriter::WriteDecl()
    @     0x564b47351725  clang::ASTWriter::WriteDeclAndTypes()
    @     0x564b4734b42b  clang::ASTWriter::WriteASTCore()
    @     0x564b4734a131  clang::ASTWriter::WriteAST()
    @     0x564b473bb1e0  clang::PCHGenerator::HandleTranslationUnit()
    @     0x564b46f27cfd  clang::MultiplexConsumer::HandleTranslationUnit()
    @     0x564b4713a948  clang::ParseAST()
    @     0x564b46e6e34a  clang::FrontendAction::Execute()
    @     0x564b46de125d  clang::CompilerInstance::ExecuteAction()
    @     0x564b4622586b  clang::ExecuteCompilerInvocation()
    @     0x564b46219218  cc1_main()
    @     0x564b46216334  ExecuteCC1Tool()
    @     0x564b46f97a3e  llvm::function_ref<>::callback_fn<>()
    @     0x564b4bd95c9c  llvm::CrashRecoveryContext::RunSafely()
    @     0x564b46f96f24  clang::driver::CC1Command::Execute()
    @     0x564b46f57615  clang::driver::Compilation::ExecuteCommand()
    @     0x564b46f578af  clang::driver::Compilation::ExecuteJobs()
    @     0x564b46f73200  clang::driver::Driver::ExecuteCompilation()
    @     0x564b4621593d  clang_main()
    @     0x564b46213cf4  main
    @     0x7f816c5b43d4  __libc_start_main
    @     0x564b46213c2a  _start

@hnrklssn
Copy link
Member Author

hnrklssn commented Jul 4, 2025

I patched #146468 after this change, rebuilt the compiler and reproduced the same crash. So I guess that patch does not fix the issue I see here. Does #146468 depend on some other change?

It does not. Do you have a reproducer you can share? Does the type that's being casted to RecordType have RecordType as the canonical type, or is it completely off? Perhaps it could be as simple as replacing castAs with getAs..?
You don't happen to be using the new constant interpreter?

@bgra8
Copy link
Contributor

bgra8 commented Jul 4, 2025

Do you have a reproducer you can share?

Working to get a smaller repro. But this only reproduces for builds with modules enabled so it will take some time.

Does the type that's being casted to RecordType have RecordType as the canonical type, or is it completely off?

The compiler seems to choke on serializing a const member initialized with a value of the same type as the member (but the type is the result of multiple macro expansions and I didn't have yet the time to investigate thoroughly)

You don't happen to be using the new constant interpreter?

Not sure what you mean by this. We're using the unmodified compiler and testing its correctness on google internal code.

@hnrklssn
Copy link
Member Author

hnrklssn commented Jul 4, 2025

You don't happen to be using the new constant interpreter?

Not sure what you mean by this. We're using the unmodified compiler and testing its correctness on google internal code.

Then you're likely not. I was just making sure, because the constant evaluation takes a different path if the new (experimental) constant interpreter is enabled.

@ilya-biryukov
Copy link
Contributor

Here's a small repro:

export module Foo;

export template <class Float>
struct Wrapper {
  double value;
};

export constexpr Wrapper<double> Compute() {
  return Wrapper<double>{1.0};
}

export template <typename Float>
Wrapper<Float> ComputeInFloat() {
  const Wrapper<Float> a = Compute();
  return a;
}

it fails when assertions are on: https://gcc.godbolt.org/z/vsW69z9Pd

The problem is that type of the VarDecl itself is dependent (the dependent TemplateSpecializationType) and so castAs fails.

My gut feeling is that the right fix would be to avoid running CheckEvaluationResult if VarDecl has a dependent type altogether and leave this diagnostic to template instantiations.

@hnrklssn
Copy link
Member Author

hnrklssn commented Jul 7, 2025

Here's a small repro:

export module Foo;

export template <class Float>
struct Wrapper {
  double value;
};

export constexpr Wrapper<double> Compute() {
  return Wrapper<double>{1.0};
}

export template <typename Float>
Wrapper<Float> ComputeInFloat() {
  const Wrapper<Float> a = Compute();
  return a;
}

it fails when assertions are on: https://gcc.godbolt.org/z/vsW69z9Pd

The problem is that type of the VarDecl itself is dependent (the dependent TemplateSpecializationType) and so castAs fails.

My gut feeling is that the right fix would be to avoid running CheckEvaluationResult if VarDecl has a dependent type altogether and leave this diagnostic to template instantiations.

Thanks! Opened a PR with a fix in #147378

hnrklssn added a commit that referenced this pull request Jul 7, 2025
EvaluateAsInitializer does not support evaluating values with dependent
types. This was previously guarded with a check for the initializer
expression, but it is possible for the VarDecl to have a dependent type
without the initializer having a dependent type, when the initializer is
a specialized template type and the VarDecl has the unspecialized type.
This adds a guard checking for dependence in the VarDecl type as well.
This fixes the issue raised by Google in
#145447
hnrklssn added a commit to hnrklssn/llvm-project that referenced this pull request Jul 7, 2025
EvaluateAsInitializer does not support evaluating values with dependent
types. This was previously guarded with a check for the initializer
expression, but it is possible for the VarDecl to have a dependent type
without the initializer having a dependent type, when the initializer is
a specialized template type and the VarDecl has the unspecialized type.
This adds a guard checking for dependence in the VarDecl type as well.
This fixes the issue raised by Google in
llvm#145447

(cherry picked from commit c885005)
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Jul 7, 2025
…147378)

EvaluateAsInitializer does not support evaluating values with dependent
types. This was previously guarded with a check for the initializer
expression, but it is possible for the VarDecl to have a dependent type
without the initializer having a dependent type, when the initializer is
a specialized template type and the VarDecl has the unspecialized type.
This adds a guard checking for dependence in the VarDecl type as well.
This fixes the issue raised by Google in
llvm/llvm-project#145447
hokein pushed a commit to hokein/llvm-project that referenced this pull request Jul 10, 2025
EvaluateAsInitializer does not support evaluating values with dependent
types. This was previously guarded with a check for the initializer
expression, but it is possible for the VarDecl to have a dependent type
without the initializer having a dependent type, when the initializer is
a specialized template type and the VarDecl has the unspecialized type.
This adds a guard checking for dependence in the VarDecl type as well.
This fixes the issue raised by Google in
llvm#145447
hokein pushed a commit to hokein/llvm-project that referenced this pull request Jul 16, 2025
EvaluateAsInitializer does not support evaluating values with dependent
types. This was previously guarded with a check for the initializer
expression, but it is possible for the VarDecl to have a dependent type
without the initializer having a dependent type, when the initializer is
a specialized template type and the VarDecl has the unspecialized type.
This adds a guard checking for dependence in the VarDecl type as well.
This fixes the issue raised by Google in
llvm#145447
hnrklssn added a commit to hnrklssn/llvm-project that referenced this pull request Sep 11, 2025
EvaluateAsInitializer does not support evaluating values with dependent
types. This was previously guarded with a check for the initializer
expression, but it is possible for the VarDecl to have a dependent type
without the initializer having a dependent type, when the initializer is
a specialized template type and the VarDecl has the unspecialized type.
This adds a guard checking for dependence in the VarDecl type as well.
This fixes the issue raised by Google in
llvm#145447

(cherry picked from commit c885005)
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:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants