[clang] [Clang][Sema] Apply CWG400 'Using-declarations and the "struct hack"' to C++98 mode (PR #143492)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 10 01:49:17 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Yanzuo Liu (zwuis)
<details>
<summary>Changes</summary>
It seems that we applied CWG400 to C++11 and newer version. But CWG400 should also be applied to C++98.
---
Full diff: https://github.com/llvm/llvm-project/pull/143492.diff
5 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+2)
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+23-69)
- (modified) clang/test/CXX/class.access/class.access.dcl/p1.cpp (+2-5)
- (modified) clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp (+6-19)
- (modified) clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp (+2-10)
``````````diff
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 at -2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error at -4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
- // expected-error at -5 {{using declaration refers to its own class}}
#endif
+ // expected-error at -6 {{using declaration refers to its own class}}
Subclass::foo; // legal in C++03
#if __cplusplus <= 199711L
// expected-warning at -2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error at -4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
- // expected-error at -5 {{using declaration refers into 'Subclass', which is not a base class of 'C'}}
#endif
+ // expected-error at -6 {{using declaration refers into 'Subclass', which is not a base class of 'C'}}
int bar();
-#if __cplusplus <= 199711L
- //expected-note at -2 {{target of using declaration}}
-#endif
C::bar;
#if __cplusplus <= 199711L
// expected-warning at -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 at -5 {{using declaration refers into 'D', which is not a base class of 'D2'}}
- // expected-error at -5 {{using declaration refers into 'D', which is not a base class of 'D2'}}
- // expected-error at -5 {{using declaration refers into 'D', which is not a base class of 'D2'}}
- // expected-error at -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 at -3 {{refers to its own class}}
- // expected-error at -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 at -3 {{refers to its own class}}
- // expected-error at -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 at -2 {{target of using declaration}}
-#endif
using C::bar; // expected-error {{refers to its own class}}
};
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/143492
More information about the cfe-commits
mailing list