Skip to content

Commit 3f193bc

Browse files
ChuanqiXu9tru
authored andcommitted
[C++20] [Modules] Don't diagnose duplicated implicit decl in multiple named modules (#102423)
Close #102360 Close #102349 http://eel.is/c++draft/basic.def.odr#15.3 makes it clear that the duplicated deinition are not allowed to be attached to named modules. But we need to filter the implicit declarations as user can do nothing about it and the diagnostic message is annoying. (cherry picked from commit e72d956)
1 parent 2c29bd3 commit 3f193bc

File tree

3 files changed

+154
-16
lines changed

3 files changed

+154
-16
lines changed

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3684,6 +3684,54 @@ static void inheritDefaultTemplateArguments(ASTContext &Context,
36843684
}
36853685
}
36863686

3687+
// [basic.link]/p10:
3688+
// If two declarations of an entity are attached to different modules,
3689+
// the program is ill-formed;
3690+
static void checkMultipleDefinitionInNamedModules(ASTReader &Reader, Decl *D,
3691+
Decl *Previous) {
3692+
Module *M = Previous->getOwningModule();
3693+
3694+
// We only care about the case in named modules.
3695+
if (!M || !M->isNamedModule())
3696+
return;
3697+
3698+
// If it is previous implcitly introduced, it is not meaningful to
3699+
// diagnose it.
3700+
if (Previous->isImplicit())
3701+
return;
3702+
3703+
// FIXME: Get rid of the enumeration of decl types once we have an appropriate
3704+
// abstract for decls of an entity. e.g., the namespace decl and using decl
3705+
// doesn't introduce an entity.
3706+
if (!isa<VarDecl, FunctionDecl, TagDecl, RedeclarableTemplateDecl>(Previous))
3707+
return;
3708+
3709+
// Skip implicit instantiations since it may give false positive diagnostic
3710+
// messages.
3711+
// FIXME: Maybe this shows the implicit instantiations may have incorrect
3712+
// module owner ships. But given we've finished the compilation of a module,
3713+
// how can we add new entities to that module?
3714+
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Previous);
3715+
VTSD && !VTSD->isExplicitSpecialization())
3716+
return;
3717+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Previous);
3718+
CTSD && !CTSD->isExplicitSpecialization())
3719+
return;
3720+
if (auto *Func = dyn_cast<FunctionDecl>(Previous))
3721+
if (auto *FTSI = Func->getTemplateSpecializationInfo();
3722+
FTSI && !FTSI->isExplicitSpecialization())
3723+
return;
3724+
3725+
// It is fine if they are in the same module.
3726+
if (Reader.getContext().isInSameModule(M, D->getOwningModule()))
3727+
return;
3728+
3729+
Reader.Diag(Previous->getLocation(),
3730+
diag::err_multiple_decl_in_different_modules)
3731+
<< cast<NamedDecl>(Previous) << M->Name;
3732+
Reader.Diag(D->getLocation(), diag::note_also_found);
3733+
}
3734+
36873735
void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
36883736
Decl *Previous, Decl *Canon) {
36893737
assert(D && Previous);
@@ -3697,22 +3745,7 @@ void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
36973745
#include "clang/AST/DeclNodes.inc"
36983746
}
36993747

3700-
// [basic.link]/p10:
3701-
// If two declarations of an entity are attached to different modules,
3702-
// the program is ill-formed;
3703-
//
3704-
// FIXME: Get rid of the enumeration of decl types once we have an appropriate
3705-
// abstract for decls of an entity. e.g., the namespace decl and using decl
3706-
// doesn't introduce an entity.
3707-
if (Module *M = Previous->getOwningModule();
3708-
M && M->isNamedModule() &&
3709-
isa<VarDecl, FunctionDecl, TagDecl, RedeclarableTemplateDecl>(Previous) &&
3710-
!Reader.getContext().isInSameModule(M, D->getOwningModule())) {
3711-
Reader.Diag(Previous->getLocation(),
3712-
diag::err_multiple_decl_in_different_modules)
3713-
<< cast<NamedDecl>(Previous) << M->Name;
3714-
Reader.Diag(D->getLocation(), diag::note_also_found);
3715-
}
3748+
checkMultipleDefinitionInNamedModules(Reader, D, Previous);
37163749

37173750
// If the declaration was visible in one module, a redeclaration of it in
37183751
// another module remains visible even if it wouldn't be visible by itself.

clang/test/Modules/pr102349.cppm

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \
7+
// RUN: -fprebuilt-module-path=%t
8+
// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface -o %t/c.pcm \
9+
// RUN: -fprebuilt-module-path=%t
10+
// RUN: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify \
11+
// RUN: -fprebuilt-module-path=%t
12+
13+
//--- a.cppm
14+
export module a;
15+
16+
export template<typename>
17+
struct a;
18+
19+
template<typename>
20+
struct a {
21+
};
22+
23+
export template<typename T>
24+
constexpr auto aa = a<T>();
25+
26+
//--- b.cppm
27+
export module b;
28+
29+
import a;
30+
31+
static void b() {
32+
static_cast<void>(a<void>());
33+
}
34+
35+
//--- c.cppm
36+
export module c;
37+
38+
import a;
39+
40+
static void c() {
41+
static_cast<void>(aa<void>);
42+
}
43+
44+
//--- d.cpp
45+
// expected-no-diagnostics
46+
import a;
47+
import b;
48+
import c;
49+
50+
static void d() {
51+
static_cast<void>(a<void>());
52+
}

clang/test/Modules/pr102360.cppm

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \
7+
// RUN: -fprebuilt-module-path=%t
8+
// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface -o %t/c.pcm \
9+
// RUN: -fprebuilt-module-path=%t
10+
// RUN: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify \
11+
// RUN: -fprebuilt-module-path=%t
12+
13+
//--- a.cppm
14+
export module a;
15+
16+
template<typename>
17+
constexpr auto impl = true;
18+
19+
export template<typename T>
20+
void a() {
21+
}
22+
23+
export template<typename T> requires impl<T>
24+
void a() {
25+
}
26+
27+
//--- b.cppm
28+
export module b;
29+
30+
import a;
31+
32+
static void b() {
33+
a<void>();
34+
}
35+
36+
//--- c.cppm
37+
export module c;
38+
39+
import a;
40+
41+
static void c() {
42+
a<void>();
43+
}
44+
45+
//--- d.cpp
46+
// expected-no-diagnostics
47+
import a;
48+
import b;
49+
import c;
50+
51+
static void d() {
52+
a<void>();
53+
}

0 commit comments

Comments
 (0)