Skip to content

Commit cf7a34d

Browse files
ChuanqiXu9AlexisPerry
authored andcommitted
[C++20] [Modules] Diagnose redeclarations from different modules
[basic.link]/p10: > If two declarations of an entity are attached to different modules, > the program is ill-formed But we only implemented the check for ODR. In this patch, we tried to diagnose the redeclarations from different modules.
1 parent 38ebf78 commit cf7a34d

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6075,6 +6075,9 @@ def err_thread_thread_different_kind : Error<
60756075
def err_mismatched_owning_module : Error<
60766076
"declaration of %0 in %select{the global module|module %2}1 follows "
60776077
"declaration in %select{the global module|module %4}3">;
6078+
def err_multiple_decl_in_different_modules : Error<
6079+
"declaration %0 attached to named module '%1' can't be attached to "
6080+
"other modules">;
60786081
def err_redefinition_different_type : Error<
60796082
"redefinition of %0 with a different type%diff{: $ vs $|}1,2">;
60806083
def err_redefinition_different_kind : Error<

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3723,6 +3723,23 @@ void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
37233723
#include "clang/AST/DeclNodes.inc"
37243724
}
37253725

3726+
// [basic.link]/p10:
3727+
// If two declarations of an entity are attached to different modules,
3728+
// the program is ill-formed;
3729+
//
3730+
// FIXME: Get rid of the enumeration of decl types once we have an appropriate
3731+
// abstract for decls of an entity. e.g., the namespace decl and using decl
3732+
// doesn't introduce an entity.
3733+
if (Module *M = Previous->getOwningModule();
3734+
M && M->isNamedModule() &&
3735+
isa<VarDecl, FunctionDecl, TagDecl, RedeclarableTemplateDecl>(Previous) &&
3736+
!Reader.getContext().isInSameModule(M, D->getOwningModule())) {
3737+
Reader.Diag(Previous->getLocation(),
3738+
diag::err_multiple_decl_in_different_modules)
3739+
<< cast<NamedDecl>(Previous) << M->Name;
3740+
Reader.Diag(D->getLocation(), diag::note_also_found);
3741+
}
3742+
37263743
// If the declaration was visible in one module, a redeclaration of it in
37273744
// another module remains visible even if it wouldn't be visible by itself.
37283745
//

clang/test/Modules/no-eager-load.cppm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ void use() {
4444
// expected-note@* {{but in 'a' found a different body}}
4545
}
4646

47+
// [email protected]:* {{declaration 'foo' attached to named module 'a' can't be attached to other modules}}
48+
49+
4750
//--- h.cppm
4851
export module h;
4952
export import a;
@@ -55,3 +58,6 @@ void use() {
5558
foo(); // expected-error@* {{'foo' has different definitions in different modules;}}
5659
// expected-note@* {{but in 'a' found a different body}}
5760
}
61+
62+
// [email protected]:* {{declaration 'foo' attached to named module 'a' can't be attached to other modules}}
63+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/mod1.cppm -emit-module-interface -o %t/mod1.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/mod2.cppm -emit-module-interface -o %t/mod2.pcm
7+
// RUN: %clang_cc1 -std=c++20 %t/test.cc -fprebuilt-module-path=%t -fsyntax-only -verify
8+
9+
//--- mod1.cppm
10+
export module mod1;
11+
export int v;
12+
export void func();
13+
export class A {};
14+
export template <class C>
15+
struct S {};
16+
17+
//--- mod2.cppm
18+
export module mod2;
19+
export int v;
20+
export void func();
21+
export class A;
22+
export template <class C>
23+
struct S {};
24+
25+
//--- test.cc
26+
import mod1;
27+
import mod2;
28+
void test() {
29+
int value = v;
30+
func();
31+
A a;
32+
S<int> s;
33+
}
34+
35+
// [email protected]:* {{declaration 'v' attached to named module 'mod1' can't be attached to other modules}}
36+
37+
// [email protected]:* {{declaration 'func' attached to named module 'mod1' can't be attached to other modules}}
38+
39+
// [email protected]:* {{declaration 'A' attached to named module 'mod1' can't be attached to other modules}}
40+
41+
// [email protected]:* 1+{{declaration 'S' attached to named module 'mod1' can't be attached to other modules}}
42+
// [email protected]:* 1+{{}}

0 commit comments

Comments
 (0)