aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>2025-08-19 23:27:10 +0800
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>2025-08-20 11:47:00 +0800
commit2db239acd1e4cb61e8c5c55dcc4b08c7d64919b6 (patch)
tree02988197e98bc10363df2842f8b1a40840f41182 /clang/lib
parent78e3ab306f1b6bb18955f80dbd578b0042df9cee (diff)
downloadllvm-2db239acd1e4cb61e8c5c55dcc4b08c7d64919b6.zip
llvm-2db239acd1e4cb61e8c5c55dcc4b08c7d64919b6.tar.gz
llvm-2db239acd1e4cb61e8c5c55dcc4b08c7d64919b6.tar.bz2
[C++20] [Modules] Improve the import-and-include pattern
The import and include problem is a long-standing issue with the use of C++20 modules. This patch tried to improve this by skipping parsing class and functions if their declaration is already defined in modules. The scale of the patch itself is small as the patch reuses previous optimization. Maybe we can skip parsing other declarations in the future. But the patch itself should be good.
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp43
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp24
2 files changed, 45 insertions, 22 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 8ddbaf3..d419f66 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15837,17 +15837,18 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
if (TypoCorrectedFunctionDefinitions.count(Definition))
return;
- // If we don't have a visible definition of the function, and it's inline or
- // a template, skip the new definition.
- if (SkipBody && !hasVisibleDefinition(Definition) &&
+ bool DefinitionVisible = false;
+ if (SkipBody && isRedefinitionAllowedFor(Definition, DefinitionVisible) &&
(Definition->getFormalLinkage() == Linkage::Internal ||
Definition->isInlined() || Definition->getDescribedFunctionTemplate() ||
Definition->getNumTemplateParameterLists())) {
SkipBody->ShouldSkip = true;
SkipBody->Previous = const_cast<FunctionDecl*>(Definition);
- if (auto *TD = Definition->getDescribedFunctionTemplate())
- makeMergedDefinitionVisible(TD);
- makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition));
+ if (!DefinitionVisible) {
+ if (auto *TD = Definition->getDescribedFunctionTemplate())
+ makeMergedDefinitionVisible(TD);
+ makeMergedDefinitionVisible(const_cast<FunctionDecl *>(Definition));
+ }
return;
}
@@ -18196,8 +18197,10 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
// However, ensure the decl passes the structural compatibility
// check in C11 6.2.7/1 (or 6.1.2.6/1 in C89).
NamedDecl *Hidden = nullptr;
- if (SkipBody && (!hasVisibleDefinition(Def, &Hidden) ||
- getLangOpts().C23)) {
+ bool HiddenDefVisible = false;
+ if (SkipBody &&
+ (isRedefinitionAllowedFor(Def, &Hidden, HiddenDefVisible) ||
+ getLangOpts().C23)) {
// There is a definition of this tag, but it is not visible.
// We explicitly make use of C++'s one definition rule here,
// and assume that this definition is identical to the hidden
@@ -18213,13 +18216,15 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
ProcessDeclAttributeList(S, SkipBody->New, Attrs);
return Def;
- } else {
- SkipBody->ShouldSkip = true;
- SkipBody->Previous = Def;
- makeMergedDefinitionVisible(Hidden);
- // Carry on and handle it like a normal definition. We'll
- // skip starting the definition later.
}
+
+ SkipBody->ShouldSkip = true;
+ SkipBody->Previous = Def;
+ if (!HiddenDefVisible && Hidden)
+ makeMergedDefinitionVisible(Hidden);
+ // Carry on and handle it like a normal definition. We'll
+ // skip starting the definition later.
+
} else if (!IsExplicitSpecializationAfterInstantiation) {
// A redeclaration in function prototype scope in C isn't
// visible elsewhere, so merely issue a warning.
@@ -20842,3 +20847,13 @@ bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) {
return LangOpts.CUDA && !LangOpts.CUDAIsDevice &&
CUDA().IdentifyTarget(Callee) == CUDAFunctionTarget::Global;
}
+
+bool Sema::isRedefinitionAllowedFor(NamedDecl *D, NamedDecl **Suggested,
+ bool &Visible) {
+ Visible = hasVisibleDefinition(D, Suggested);
+ // The redefinition of D in the **current** TU is allowed if D is invisible or
+ // D is defined in the global module of other module units. We didn't check if
+ // it is in global module as, we'll check the redefinition in named module
+ // later with better diagnostic message.
+ return D->isInAnotherModuleUnit() || !Visible;
+}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 72d98ca..0edc850 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2078,14 +2078,19 @@ DeclResult Sema::CheckClassTemplate(
// If we have a prior definition that is not visible, treat this as
// simply making that previous definition visible.
NamedDecl *Hidden = nullptr;
- if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
+ bool HiddenDefVisible = false;
+ if (SkipBody &&
+ isRedefinitionAllowedFor(Def, &Hidden, HiddenDefVisible)) {
SkipBody->ShouldSkip = true;
SkipBody->Previous = Def;
- auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
- assert(Tmpl && "original definition of a class template is not a "
- "class template?");
- makeMergedDefinitionVisible(Hidden);
- makeMergedDefinitionVisible(Tmpl);
+ if (!HiddenDefVisible && Hidden) {
+ auto *Tmpl =
+ cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
+ assert(Tmpl && "original definition of a class template is not a "
+ "class template?");
+ makeMergedDefinitionVisible(Hidden);
+ makeMergedDefinitionVisible(Tmpl);
+ }
} else {
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
@@ -8956,10 +8961,13 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
if (TUK == TagUseKind::Definition) {
RecordDecl *Def = Specialization->getDefinition();
NamedDecl *Hidden = nullptr;
- if (Def && SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
+ bool HiddenDefVisible = false;
+ if (Def && SkipBody &&
+ isRedefinitionAllowedFor(Def, &Hidden, HiddenDefVisible)) {
SkipBody->ShouldSkip = true;
SkipBody->Previous = Def;
- makeMergedDefinitionVisible(Hidden);
+ if (!HiddenDefVisible && Hidden)
+ makeMergedDefinitionVisible(Hidden);
} else if (Def) {
SourceRange Range(TemplateNameLoc, RAngleLoc);
Diag(TemplateNameLoc, diag::err_redefinition) << Specialization << Range;