diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 6643370525001..45e73226d706b 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -83,6 +83,17 @@ bool Parser::isCXXDeclarationStatement( isDeductionGuide, DeclSpec::FriendSpecified::No)) return true; + } else if (SS.isNotEmpty()) { + // If the scope is not empty, it could alternatively be something like + // a typedef or using declaration. That declaration might be private + // in the global context, which would be diagnosed by calling into + // isCXXSimpleDeclaration, but may actually be fine in the context of + // member functions and static variable definitions. Check if the next + // token is also an identifier and assume a declaration. + // We cannot check if the scopes match because the declarations could + // involve namespaces and friend declarations. + if (NextToken().is(tok::identifier)) + return true; } break; } diff --git a/clang/test/Interpreter/disambiguate-decl-stmt.cpp b/clang/test/Interpreter/disambiguate-decl-stmt.cpp index cbc456da6eb51..a49d7013c540a 100644 --- a/clang/test/Interpreter/disambiguate-decl-stmt.cpp +++ b/clang/test/Interpreter/disambiguate-decl-stmt.cpp @@ -1,8 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -fincremental-extensions -std=c++20 %s // RUN: %clang_cc1 -fsyntax-only -DMS -fms-extensions -verify -fincremental-extensions -std=c++20 %s -// expected-no-diagnostics - extern "C" int printf(const char*,...); // Decls which are hard to disambiguate @@ -47,6 +45,37 @@ ANestedDtor::A1::A2::~A2() { printf("Dtor A::A1::A2::~A2\n"); } // Ctors +// Private typedefs / using declarations +class PrivateUsingMember { using T = int; T f(); }; +PrivateUsingMember::T PrivateUsingMember::f() { return 0; } + +class PrivateUsingVar { using T = int; static T i; }; +PrivateUsingVar::T PrivateUsingVar::i = 42; + +// The same with namespaces +namespace PrivateUsingNamespace { class Member { using T = int; T f(); }; } +PrivateUsingNamespace::Member::T PrivateUsingNamespace::Member::f() { return 0; } + +namespace PrivateUsingNamespace { class Var { using T = int; static T i; }; } +PrivateUsingNamespace::Var::T PrivateUsingNamespace::Var::i = 42; + +// The same with friend declarations +class PrivateUsingFriendMember; +class PrivateUsingFriendVar; +class PrivateUsingFriend { friend class PrivateUsingFriendMember; friend class PrivateUsingFriendVar; using T = int; }; +class PrivateUsingFriendMember { PrivateUsingFriend::T f(); }; +PrivateUsingFriend::T PrivateUsingFriendMember::f() { return 0; } + +class PrivateUsingFriendVar { static PrivateUsingFriend::T i; }; +PrivateUsingFriend::T PrivateUsingFriendVar::i = 42; + +// The following should still diagnose (inspired by PR13642) +// FIXME: Should not be diagnosed twice! +class PR13642 { class Inner { public: static int i; }; }; +// expected-note@-1 2 {{implicitly declared private here}} +PR13642::Inner::i = 5; +// expected-error@-1 2 {{'Inner' is a private member of 'PR13642'}} + // Deduction guide template struct A { A(); A(T); }; A() -> A;