Skip to content
Merged
10 changes: 6 additions & 4 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6092,12 +6092,14 @@ void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,

// An updated body is emitted last, so that the reader doesn't need
// to skip over the lazy body to reach statements for other records.
if (Kind == UPD_CXX_ADDED_FUNCTION_DEFINITION)
HasUpdatedBody = true;
else if (Kind == UPD_CXX_ADDED_VAR_DEFINITION)
if (Kind == UPD_CXX_ADDED_FUNCTION_DEFINITION) {
assert(isa<FunctionDecl>(D) && "expected FunctionDecl");
HasUpdatedBody = cast<FunctionDecl>(D)->hasBody();
Copy link
Member

Choose a reason for hiding this comment

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

Sorry to skip this on the last iteration. We should use doesThisDeclarationHaveABody instead of hasBody. Since hasBody may be more expensive.

And also it is still slightly better to not set UPD_CXX_ADDED_FUNCTION_DEFINITION if the function doesn't have a body. We can check this in CompletedImplicitDefinition and VariableDefinitionInstantiated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No problem! I want the get it right, not to rush it :D

Changed, although I imagine you meant FunctionDefinitionInstantiated (not VariableDefinitionInstantiated)

} else if (Kind == UPD_CXX_ADDED_VAR_DEFINITION) {
HasAddedVarDefinition = true;
else
} else {
Record.push_back(Kind);
}

switch (Kind) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
Expand Down
42 changes: 42 additions & 0 deletions clang/test/Modules/missing-body-in-import.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: cd %t

// RUN: %clang_cc1 -std=c++23 mod1.cppm -emit-module-interface -o mod1.pcm -fallow-pcm-with-compiler-errors -verify
// RUN: %clang_cc1 -std=c++23 mod2.cppm -emit-module-interface -o mod2.pcm -fmodule-file=mod1=mod1.pcm -verify -fallow-pcm-with-compiler-errors
// RUN: %clang_cc1 -std=c++23 mod3.cppm -emit-module-interface -o mod3.pcm -fmodule-file=mod1=mod1.pcm -fmodule-file=mod2=mod2.pcm -verify -fallow-pcm-with-compiler-errors
// RUN: %clang_cc1 -std=c++23 main.cpp -fmodule-file=mod1=mod1.pcm -fmodule-file=mod2=mod2.pcm -fmodule-file=mod3=mod3.pcm -verify -fallow-pcm-with-compiler-errors -ast-dump-all

//--- mod1.cppm
export module mod1;

export template <unsigned N, unsigned M>
class A {
public:
constexpr A(const char[], const char[]) {
auto x = BrokenExpr; // expected-error {{use of undeclared identifier 'BrokenExpr'}}
}
};

export template<A<1,1> NTTP>
struct B {};

template < unsigned N, unsigned M >
A(const char (&)[N], const char (&)[M]) -> A< 1, 1 >;

//--- mod2.cppm
export module mod2;
import mod1;

struct C: B <A{"a", "b"}> { // expected-error {{non-type template argument is not a constant expression}}
constexpr C(int a) { }
};

//--- mod3.cppm
// expected-no-diagnostics
export module mod3;
export import mod2;

//--- main.cpp
// expected-no-diagnostics
import mod3; // no crash
Loading