https://github.com/zwuis created https://github.com/llvm/llvm-project/pull/143492
It seems that we applied CWG400 to C++11 and newer version. But CWG400 should also be applied to C++98. >From 658f3d3cb72ff9fbdb2315f894f39956eeabf135 Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <zw...@outlook.com> Date: Tue, 10 Jun 2025 16:41:57 +0800 Subject: [PATCH] Apply CWG400 'Using-declarations and the "struct hack"' to C++98 mode --- clang/docs/ReleaseNotes.rst | 2 + clang/lib/Sema/SemaDeclCXX.cpp | 92 +++++-------------- .../CXX/class.access/class.access.dcl/p1.cpp | 7 +- .../basic.namespace/namespace.udecl/p3.cpp | 25 ++--- .../basic.namespace/namespace.udecl/p4.cpp | 12 +-- 5 files changed, 35 insertions(+), 103 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index beed0da6883d6..d8f09a275c1f0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -840,6 +840,8 @@ Bug Fixes to C++ Support - Fixed a pack substitution bug in deducing class template partial specializations. (#GH53609) - Fixed a crash when constant evaluating some explicit object member assignment operators. (#GH142835) - Fixed an access checking bug when substituting into concepts (#GH115838) +- Correctly rejects invalid member using-declaration whose nested name specifier + refers to its own class in C++98 mode. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5ef2ae3ee857f..84c666578b79a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -13632,82 +13632,36 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), NamedContext)) return true; - if (getLangOpts().CPlusPlus11) { - // C++11 [namespace.udecl]p3: - // In a using-declaration used as a member-declaration, the - // nested-name-specifier shall name a base class of the class - // being defined. + // CWG400 [namespace.udecl]p3: + // In a using-declaration used as a member-declaration, the + // nested-name-specifier shall name a base class of the class being defined. - if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom( - cast<CXXRecordDecl>(NamedContext))) { + if (cast<CXXRecordDecl>(CurContext) + ->isProvablyNotDerivedFrom(cast<CXXRecordDecl>(NamedContext))) { - if (Cxx20Enumerator) { - Diag(NameLoc, diag::warn_cxx17_compat_using_decl_non_member_enumerator) - << SS.getRange(); - return false; - } - - if (CurContext == NamedContext) { - Diag(SS.getBeginLoc(), - diag::err_using_decl_nested_name_specifier_is_current_class) - << SS.getRange(); - return !getLangOpts().CPlusPlus20; - } - - if (!cast<CXXRecordDecl>(NamedContext)->isInvalidDecl()) { - Diag(SS.getBeginLoc(), - diag::err_using_decl_nested_name_specifier_is_not_base_class) - << SS.getScopeRep() << cast<CXXRecordDecl>(CurContext) - << SS.getRange(); - } - return true; + if (Cxx20Enumerator) { + Diag(NameLoc, diag::warn_cxx17_compat_using_decl_non_member_enumerator) + << SS.getRange(); + return false; } - return false; - } - - // C++03 [namespace.udecl]p4: - // A using-declaration used as a member-declaration shall refer - // to a member of a base class of the class being defined [etc.]. - - // Salient point: SS doesn't have to name a base class as long as - // lookup only finds members from base classes. Therefore we can - // diagnose here only if we can prove that can't happen, - // i.e. if the class hierarchies provably don't intersect. - - // TODO: it would be nice if "definitely valid" results were cached - // in the UsingDecl and UsingShadowDecl so that these checks didn't - // need to be repeated. + if (CurContext == NamedContext) { + Diag(SS.getBeginLoc(), + diag::err_using_decl_nested_name_specifier_is_current_class) + << SS.getRange(); + return !getLangOpts().CPlusPlus20; + } - llvm::SmallPtrSet<const CXXRecordDecl *, 4> Bases; - auto Collect = [&Bases](const CXXRecordDecl *Base) { - Bases.insert(Base); + if (!cast<CXXRecordDecl>(NamedContext)->isInvalidDecl()) { + Diag(SS.getBeginLoc(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << SS.getScopeRep() << cast<CXXRecordDecl>(CurContext) + << SS.getRange(); + } return true; - }; - - // Collect all bases. Return false if we find a dependent base. - if (!cast<CXXRecordDecl>(CurContext)->forallBases(Collect)) - return false; - - // Returns true if the base is dependent or is one of the accumulated base - // classes. - auto IsNotBase = [&Bases](const CXXRecordDecl *Base) { - return !Bases.count(Base); - }; - - // Return false if the class has a dependent base or if it or one - // of its bases is present in the base set of the current context. - if (Bases.count(cast<CXXRecordDecl>(NamedContext)) || - !cast<CXXRecordDecl>(NamedContext)->forallBases(IsNotBase)) - return false; - - Diag(SS.getRange().getBegin(), - diag::err_using_decl_nested_name_specifier_is_not_base_class) - << SS.getScopeRep() - << cast<CXXRecordDecl>(CurContext) - << SS.getRange(); + } - return true; + return false; } Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, diff --git a/clang/test/CXX/class.access/class.access.dcl/p1.cpp b/clang/test/CXX/class.access/class.access.dcl/p1.cpp index fdb1373dd9b12..1ad4135e32ba5 100644 --- a/clang/test/CXX/class.access/class.access.dcl/p1.cpp +++ b/clang/test/CXX/class.access/class.access.dcl/p1.cpp @@ -323,21 +323,18 @@ namespace test4 { // expected-warning@-2 {{access declarations are deprecated; use using declarations instead}} #else // expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}} - // expected-error@-5 {{using declaration refers to its own class}} #endif + // expected-error@-6 {{using declaration refers to its own class}} Subclass::foo; // legal in C++03 #if __cplusplus <= 199711L // expected-warning@-2 {{access declarations are deprecated; use using declarations instead}} #else // expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}} - // expected-error@-5 {{using declaration refers into 'Subclass', which is not a base class of 'C'}} #endif + // expected-error@-6 {{using declaration refers into 'Subclass', which is not a base class of 'C'}} int bar(); -#if __cplusplus <= 199711L - //expected-note@-2 {{target of using declaration}} -#endif C::bar; #if __cplusplus <= 199711L // expected-warning@-2 {{access declarations are deprecated; use using declarations instead}} diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp index 657695657e0f7..bcc26bf4f4356 100644 --- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp @@ -30,17 +30,10 @@ class D2 : public B { using B::x; using C::g; // expected-error{{using declaration refers into 'C', which is not a base class of 'D2'}} - // These are valid in C++98 but not in C++11. - using D::f2; - using D::E2; - using D::e2; - using D::x2; -#if __cplusplus >= 201103L - // expected-error@-5 {{using declaration refers into 'D', which is not a base class of 'D2'}} - // expected-error@-5 {{using declaration refers into 'D', which is not a base class of 'D2'}} - // expected-error@-5 {{using declaration refers into 'D', which is not a base class of 'D2'}} - // expected-error@-5 {{using declaration refers into 'D', which is not a base class of 'D2'}} -#endif + using D::f2; // expected-error {{using declaration refers into 'D', which is not a base class of 'D2'}} + using D::E2; // expected-error {{using declaration refers into 'D', which is not a base class of 'D2'}} + using D::e2; // expected-error {{using declaration refers into 'D', which is not a base class of 'D2'}} + using D::x2; // expected-error {{using declaration refers into 'D', which is not a base class of 'D2'}} using B::EC; using B::EC::ec; // expected-warning {{a C++20 extension}} expected-warning 0-1 {{C++11}} @@ -71,13 +64,7 @@ namespace test1 { using Base::bar; // expected-error {{no member named 'bar'}} using Unrelated::foo; // expected-error {{not a base class}} - // In C++98, it's hard to see that these are invalid, because indirect - // references to base class members are permitted. - using C::foo; - using Subclass::foo; -#if __cplusplus >= 201103L - // expected-error@-3 {{refers to its own class}} - // expected-error@-3 {{not a base class}} -#endif + using C::foo; // expected-error {{refers to its own class}} + using Subclass::foo; // expected-error {{not a base class}} }; } diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp index 973cd77279f19..26b66350b86d9 100644 --- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp @@ -206,17 +206,9 @@ namespace test4 { using InnerNS::foo; // expected-error {{not a class}} using Base::bar; // expected-error {{no member named 'bar'}} using Unrelated::foo; // expected-error {{not a base class}} - using C::foo; // legal in C++03 - using Subclass::foo; // legal in C++03 -#if __cplusplus >= 201103L - // expected-error@-3 {{refers to its own class}} - // expected-error@-3 {{refers into 'Subclass', which is not a base class}} -#endif - + using C::foo; // expected-error {{refers to its own class}} + using Subclass::foo; // expected-error {{refers into 'Subclass', which is not a base class}} int bar(); -#if __cplusplus < 201103L - // expected-note@-2 {{target of using declaration}} -#endif using C::bar; // expected-error {{refers to its own class}} }; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits