https://github.com/zhy-tju updated https://github.com/llvm/llvm-project/pull/147036
>From 4b098e63f1c1aa8bb4c7d4d1966a22c236a9ff17 Mon Sep 17 00:00:00 2001 From: zhy <2697737...@qq.com> Date: Fri, 4 Jul 2025 16:50:03 +0800 Subject: [PATCH 1/4] [Clang] Duplicate diagnostics in C++20+ mode --- clang/include/clang/Sema/DeclSpec.h | 10 ++++++++++ clang/lib/Sema/SemaCXXScopeSpec.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 567ad2d5934d4..8721b836002e2 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -76,6 +76,10 @@ class CXXScopeSpec { NestedNameSpecifierLocBuilder Builder; ArrayRef<TemplateParameterList *> TemplateParamLists; + /// Flag indicating whether an incomplete-type diagnostic + /// has already been emitted for this scope specifier. + bool HadIncompleteTypeError = false; + public: SourceRange getRange() const { return Range; } void setRange(SourceRange R) { Range = R; } @@ -83,6 +87,12 @@ class CXXScopeSpec { void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } + + /// Return true if an incomplete-type diagnostic has already been emitted. + bool hasIncompleteTypeError() const { return HadIncompleteTypeError; } + + /// Mark that an incomplete-type error was emitted for this scope. + void setIncompleteTypeError(bool v = true) { HadIncompleteTypeError = v; } void setTemplateParamLists(ArrayRef<TemplateParameterList *> L) { TemplateParamLists = L; diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index ab83f625d2849..a95d2e83768e2 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -209,10 +209,20 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, SourceLocation loc = SS.getLastQualifierNameLoc(); if (loc.isInvalid()) loc = SS.getRange().getBegin(); + // If an incomplete-type error has already been emitted for this scope, + // suppress duplicate diagnostics to avoid noisy repeated messages. + if (SS.hasIncompleteTypeError()) + return true; + // The type must be complete. if (RequireCompleteType(loc, type, diag::err_incomplete_nested_name_spec, SS.getRange())) { SS.SetInvalid(SS.getRange()); + + // Remember that we've already diagnosed this incomplete type, + // so later checks won't emit redundant diagnostics. + SS.setIncompleteTypeError(); + return true; } >From 7a111a6b45f43b84be4a33d20763fd002e501deb Mon Sep 17 00:00:00 2001 From: zhy <2697737...@qq.com> Date: Fri, 4 Jul 2025 17:19:50 +0800 Subject: [PATCH 2/4] [Clang] Duplicate diagnostics in C++20+ mode --- clang/test/SemaCXX/nested-name-spec.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/test/SemaCXX/nested-name-spec.cpp b/clang/test/SemaCXX/nested-name-spec.cpp index abeaba9d8dde2..df82d7a8dcf70 100644 --- a/clang/test/SemaCXX/nested-name-spec.cpp +++ b/clang/test/SemaCXX/nested-name-spec.cpp @@ -1,3 +1,10 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + +struct incomplete; +incomplete::type var; // expected-error{{incomplete type 'incomplete' named in nested name specifier}} +// expected-note@-2{{forward declaration of 'incomplete'}} + + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify -fblocks %s namespace A { struct C { >From 9d650488a66ae47878ca5d13c3353da7bb4dac38 Mon Sep 17 00:00:00 2001 From: zhy <2697737...@qq.com> Date: Fri, 4 Jul 2025 18:27:28 +0800 Subject: [PATCH 3/4] [Clang] Duplicate diagnostics --- clang/include/clang/Sema/DeclSpec.h | 10 ---------- clang/include/clang/Sema/Sema.h | 6 ++++++ clang/lib/Sema/SemaCXXScopeSpec.cpp | 17 ++++++++--------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 8721b836002e2..567ad2d5934d4 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -76,10 +76,6 @@ class CXXScopeSpec { NestedNameSpecifierLocBuilder Builder; ArrayRef<TemplateParameterList *> TemplateParamLists; - /// Flag indicating whether an incomplete-type diagnostic - /// has already been emitted for this scope specifier. - bool HadIncompleteTypeError = false; - public: SourceRange getRange() const { return Range; } void setRange(SourceRange R) { Range = R; } @@ -87,12 +83,6 @@ class CXXScopeSpec { void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } - - /// Return true if an incomplete-type diagnostic has already been emitted. - bool hasIncompleteTypeError() const { return HadIncompleteTypeError; } - - /// Mark that an incomplete-type error was emitted for this scope. - void setIncompleteTypeError(bool v = true) { HadIncompleteTypeError = v; } void setTemplateParamLists(ArrayRef<TemplateParameterList *> L) { TemplateParamLists = L; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3fe26f950ad51..1c7a67d32cf72 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1555,6 +1555,12 @@ class Sema final : public SemaBase { Sema(const Sema &) = delete; void operator=(const Sema &) = delete; + /// Used to suppress duplicate diagnostics for incomplete types + /// in nested name specifiers (e.g. `incomplete::type`). + /// Without this, Clang may emit the same error multiple times + /// in C++20 or later, due to multiple semantic passes over the scope. + llvm::DenseSet<const TagDecl *> IncompleteDiagSet; + /// The handler for the FileChanged preprocessor events. /// /// Used for diagnostics that implement custom semantic analysis for #include diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index a95d2e83768e2..8731f3cbbb8cd 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -206,22 +206,21 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, if (tag->isBeingDefined()) return false; + // Avoid emitting duplicate diagnostics for the same tag. + // This happens in C++20+ due to more aggressive semantic analysis. + if (IncompleteDiagSet.contains(tag)) + return true; + SourceLocation loc = SS.getLastQualifierNameLoc(); if (loc.isInvalid()) loc = SS.getRange().getBegin(); - // If an incomplete-type error has already been emitted for this scope, - // suppress duplicate diagnostics to avoid noisy repeated messages. - if (SS.hasIncompleteTypeError()) - return true; - // The type must be complete. if (RequireCompleteType(loc, type, diag::err_incomplete_nested_name_spec, SS.getRange())) { - SS.SetInvalid(SS.getRange()); + // mark as diagnosed + IncompleteDiagSet.insert(tag); - // Remember that we've already diagnosed this incomplete type, - // so later checks won't emit redundant diagnostics. - SS.setIncompleteTypeError(); + SS.SetInvalid(SS.getRange()); return true; } >From cdfecb9998ec0e26f556926d0179333b6b75f8ba Mon Sep 17 00:00:00 2001 From: zhy <2697737...@qq.com> Date: Sat, 5 Jul 2025 00:50:45 +0800 Subject: [PATCH 4/4] new_change --- clang/include/clang/Sema/Sema.h | 10 +++++----- clang/lib/Sema/SemaCXXScopeSpec.cpp | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 1c7a67d32cf72..da52f682d30a8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1555,11 +1555,11 @@ class Sema final : public SemaBase { Sema(const Sema &) = delete; void operator=(const Sema &) = delete; - /// Used to suppress duplicate diagnostics for incomplete types - /// in nested name specifiers (e.g. `incomplete::type`). - /// Without this, Clang may emit the same error multiple times - /// in C++20 or later, due to multiple semantic passes over the scope. - llvm::DenseSet<const TagDecl *> IncompleteDiagSet; + /// Tracks (TagDecl, SourceLocation) pairs that have already triggered + /// an "incomplete type in nested name specifier" diagnostic, + /// to prevent emitting duplicate errors in C++20 and later, + /// where the same scope may be processed multiple times. + llvm::DenseSet<std::pair<const clang::TagDecl *, clang::SourceLocation>> DiagnosedIncompleteTypeSet; /// The handler for the FileChanged preprocessor events. /// diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 8731f3cbbb8cd..05a0c7cae6d66 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -206,20 +206,23 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, if (tag->isBeingDefined()) return false; - // Avoid emitting duplicate diagnostics for the same tag. - // This happens in C++20+ due to more aggressive semantic analysis. - if (IncompleteDiagSet.contains(tag)) - return true; - SourceLocation loc = SS.getLastQualifierNameLoc(); if (loc.isInvalid()) loc = SS.getRange().getBegin(); + // If the DeclContext is a tag declaration, form a unique key + // from the TagDecl and the source location where the scope starts. + // If this key has already been diagnosed, skip emitting the error again. + const TagDecl *Tag = dyn_cast_or_null<TagDecl>(DC); + if (Tag) { + auto Key = std::make_pair(Tag, SS.getBeginLoc()); + if (!DiagnosedIncompleteTypeSet.insert(Key).second) + return true; // Already diagnosed + } + + // The type must be complete. if (RequireCompleteType(loc, type, diag::err_incomplete_nested_name_spec, SS.getRange())) { - // mark as diagnosed - IncompleteDiagSet.insert(tag); - SS.SetInvalid(SS.getRange()); return true; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits