Author: Chuanqi Xu Date: 2026-06-03T17:19:41+08:00 New Revision: 74f1c9417e916aed314fd429ce2faee49668ffa6
URL: https://github.com/llvm/llvm-project/commit/74f1c9417e916aed314fd429ce2faee49668ffa6 DIFF: https://github.com/llvm/llvm-project/commit/74f1c9417e916aed314fd429ce2faee49668ffa6.diff LOG: [C++20] [Modules] Ask for definition before calling isInlineDefinitionExternallyVisible (#201291) Close https://github.com/llvm/llvm-project/issues/195905 The root cause of the problem is, after decl merging, one of the destructor for `base` (see test case) is chosen, and its body is not deserialized for performance as we alreday see its body in current TU. And then, the code call FunctionDecl::isInlineDefinitionExternallyVisible from the destructor without a serialized body, but FunctionDecl::isInlineDefinitionExternallyVisible's implementation requires to see a body. Then assertion failed. Decl merging and function decl merging is common. We can't always make sure we find the definition without checking. It is much more fundamental. So the PR doesn't try to touch the decl merging mechanism or how we handle the result of lookups. We tried to fix the issue at the calling point to make sure we have a definition for isInlineDefinitionExternallyVisible. Other use of isInlineDefinitionExternallyVisible does the similar thing. Added: clang/test/Modules/pr195905.cppm Modified: clang/lib/AST/ASTContext.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a401a7471e6fc..1e35aba7b2b19 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -13064,7 +13064,8 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, // GNU or C99 inline semantics. Determine whether this symbol should be // externally visible. - if (FD->isInlineDefinitionExternallyVisible()) + if (auto *Def = FD->getDefinition(); + Def && Def->isInlineDefinitionExternallyVisible()) return External; // C99 inline semantics, where the symbol is not externally visible. diff --git a/clang/test/Modules/pr195905.cppm b/clang/test/Modules/pr195905.cppm new file mode 100644 index 0000000000000..d107549ab10ea --- /dev/null +++ b/clang/test/Modules/pr195905.cppm @@ -0,0 +1,42 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++26 %t/a.cppm \ +// RUN: -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++26 %t/b.cppm \ +// RUN: -fmodule-file=a=%t/a.pcm -emit-llvm -Og -mconstructor-aliases \ +// RUN: -o - | FileCheck %t/b.cppm + +//--- base.hpp +struct base { + [[__gnu__::__gnu_inline__]] inline ~base() {} +}; + +//--- a.cppm +module; + +#include "base.hpp" + +export module a; + +export using ::base; + +//--- b.cppm +module; + +#include "base.hpp" + +export module b; + +import a; + +struct derived : base { +}; + +void f() { + derived x; +} + +// fine enough to check it won't crash +// CHECK: define {{.*}}@_ZGIW1b _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
