[clang] [Clang][Sema] access checking of friend declaration should not be delayed (PR #91430)
Qizhi Hu via cfe-commits
cfe-commits at lists.llvm.org
Wed May 8 17:39:11 PDT 2024
https://github.com/jcsxky updated https://github.com/llvm/llvm-project/pull/91430
>From 324e4361b4cb1b17065b4dc7d4bdfa41fe781e7d Mon Sep 17 00:00:00 2001
From: Qizhi Hu <836744285 at qq.com>
Date: Tue, 7 May 2024 22:32:39 +0800
Subject: [PATCH 1/2] [Clang][Sema] access checking of friend declaration
should not be delayed
---
clang/include/clang/Sema/Scope.h | 6 ++++++
clang/lib/Parse/ParseDecl.cpp | 7 +++++--
clang/lib/Sema/Scope.cpp | 2 ++
clang/lib/Sema/SemaAccess.cpp | 12 ++++++++++--
clang/test/SemaCXX/PR12361.cpp | 30 ++++++++++++++++++++++++++++++
5 files changed, 53 insertions(+), 4 deletions(-)
create mode 100644 clang/test/SemaCXX/PR12361.cpp
diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index 1752a25111a77..084db73034219 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -159,6 +159,9 @@ class Scope {
/// This is a scope of type alias declaration.
TypeAliasScope = 0x20000000,
+
+ /// This is a scope of friend declaration.
+ FriendScope = 0x40000000,
};
private:
@@ -586,6 +589,9 @@ class Scope {
/// Determine whether this scope is a type alias scope.
bool isTypeAliasScope() const { return getFlags() & Scope::TypeAliasScope; }
+ /// Determine whether this scope is a friend scope.
+ bool isFriendScope() const { return getFlags() & Scope::FriendScope; }
+
/// Returns if rhs has a higher scope depth than this.
///
/// The caller is responsible for calling this only if one of the two scopes
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 4e4b05b21383e..78a81c77f48c6 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4332,9 +4332,12 @@ void Parser::ParseDeclarationSpecifiers(
// friend
case tok::kw_friend:
- if (DSContext == DeclSpecContext::DSC_class)
+ if (DSContext == DeclSpecContext::DSC_class) {
isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID);
- else {
+ Scope *CurS = getCurScope();
+ if (!isInvalid && CurS)
+ CurS->setFlags(CurS->getFlags() | Scope::FriendScope);
+ } else {
PrevSpec = ""; // not actually used by the diagnostic
DiagID = diag::err_friend_invalid_in_context;
isInvalid = true;
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 11a41753a1bda..780aa898b1085 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -229,6 +229,8 @@ void Scope::dumpImpl(raw_ostream &OS) const {
{ClassInheritanceScope, "ClassInheritanceScope"},
{CatchScope, "CatchScope"},
{OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
+ {TypeAliasScope, "TypeAliasScope"},
+ {FriendScope, "FriendScope"},
};
for (auto Info : FlagInfo) {
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 6a707eeb66d01..72c6736bb6648 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1477,8 +1477,16 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
// void foo(A::private_type);
// void B::foo(A::private_type);
if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
- S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));
- return Sema::AR_delayed;
+ Scope *TS = S.getCurScope();
+ bool IsFriendDeclaration = false;
+ while (TS && !IsFriendDeclaration) {
+ IsFriendDeclaration = TS->isFriendScope();
+ TS = TS->getParent();
+ }
+ if (!IsFriendDeclaration) {
+ S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));
+ return Sema::AR_delayed;
+ }
}
EffectiveContext EC(S.CurContext);
diff --git a/clang/test/SemaCXX/PR12361.cpp b/clang/test/SemaCXX/PR12361.cpp
new file mode 100644
index 0000000000000..95ceb45b7ba04
--- /dev/null
+++ b/clang/test/SemaCXX/PR12361.cpp
@@ -0,0 +1,30 @@
+ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
+
+class D {
+ class E{
+ class F{}; // expected-note{{implicitly declared private here}}
+ friend void foo(D::E::F& q);
+ };
+ friend void foo(D::E::F& q); // expected-error{{'F' is a private member of 'D::E'}}
+ };
+
+void foo(D::E::F& q) {}
+
+class D1 {
+ class E1{
+ class F1{}; // expected-note{{implicitly declared private here}}
+ friend D1::E1::F1 foo1();
+ };
+ friend D1::E1::F1 foo1(); // expected-error{{'F1' is a private member of 'D1::E1'}}
+ };
+
+D1::E1::F1 foo1() { return D1::E1::F1(); }
+
+class D2 {
+ class E2{
+ class F2{};
+ friend void foo2();
+ };
+ friend void foo2(){ D2::E2::F2 c;}
+ };
>From 97723ff0ec73ac107bc74f222852e4c12b727eb0 Mon Sep 17 00:00:00 2001
From: Qizhi Hu <836744285 at qq.com>
Date: Wed, 8 May 2024 21:22:01 +0800
Subject: [PATCH 2/2] apply reviews
---
clang/docs/ReleaseNotes.rst | 1 +
clang/lib/Sema/Scope.cpp | 1 -
clang/lib/Sema/SemaAccess.cpp | 18 +++++++++++++++---
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a3c8e4141ca54..8567e20f3548d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -699,6 +699,7 @@ Bug Fixes to C++ Support
performed incorrectly when checking constraints. Fixes (#GH90349).
- Clang now allows constrained member functions to be explicitly specialized for an implicit instantiation
of a class template.
+- Fix a bug in access control checking due to dealyed checking of friend declaration. Fixes (#GH12361).
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 780aa898b1085..c08073e80ff3d 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -229,7 +229,6 @@ void Scope::dumpImpl(raw_ostream &OS) const {
{ClassInheritanceScope, "ClassInheritanceScope"},
{CatchScope, "CatchScope"},
{OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
- {TypeAliasScope, "TypeAliasScope"},
{FriendScope, "FriendScope"},
};
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 72c6736bb6648..979a64b065f3d 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1473,10 +1473,22 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
// specifier, like this:
// A::private_type A::foo() { ... }
//
- // Or we might be parsing something that will turn out to be a friend:
- // void foo(A::private_type);
- // void B::foo(A::private_type);
+ // friend declaration should not be delayed because it may lead to incorrect
+ // redeclaration chain, such as:
+ // class D {
+ // class E{
+ // class F{};
+ // friend void foo(D::E::F& q);
+ // };
+ // friend void foo(D::E::F& q);
+ // };
if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ // [class.friend]p9:
+ // A member nominated by a friend declaration shall be accessible in the
+ // class containing the friend declaration. The meaning of the friend
+ // declaration is the same whether the friend declaration appears in the
+ // private, protected, or public ([class.mem]) portion of the class
+ // member-specification.
Scope *TS = S.getCurScope();
bool IsFriendDeclaration = false;
while (TS && !IsFriendDeclaration) {
More information about the cfe-commits
mailing list