diff --git a/clang/include/clang/Sema/DelayedDiagnostic.h b/clang/include/clang/Sema/DelayedDiagnostic.h --- a/clang/include/clang/Sema/DelayedDiagnostic.h +++ b/clang/include/clang/Sema/DelayedDiagnostic.h @@ -312,6 +312,14 @@ pool.Diagnostics.clear(); } + void removeAllOfKind(DelayedDiagnostic::DDKind Kind) { + Diagnostics.erase(std::remove_if(Diagnostics.begin(), Diagnostics.end(), + [Kind](const DelayedDiagnostic &DD) { + return DD.Kind == Kind; + }), + Diagnostics.end()); + } + using pool_iterator = SmallVectorImpl::const_iterator; pool_iterator pool_begin() const { return Diagnostics.begin(); } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2998,7 +2998,7 @@ // the token as an identifier. if (getLangOpts().MSVCCompat && Tok.is(tok::kw__Atomic) && DS.getStorageClassSpec() == clang::DeclSpec::SCS_typedef && - !DS.hasTypeSpecifier() && GetLookAheadToken(1).is(tok::less)) + !DS.hasTypeSpecifier() && NextToken().is(tok::less)) Tok.setKind(tok::identifier); SourceLocation Loc = Tok.getLocation(); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1422,8 +1422,7 @@ // Note that we don't suppress if this turns out to be an elaborated // type specifier. bool shouldDelayDiagsInTag = - (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate); SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag); ParsedAttributesWithRange attrs(AttrFactory); @@ -1770,14 +1769,6 @@ } } - // If this is an elaborated type specifier, and we delayed - // diagnostics before, just merge them into the current pool. - if (shouldDelayDiagsInTag) { - diagsFromTag.done(); - if (TUK == Sema::TUK_Reference) - diagsFromTag.redelay(); - } - if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || TUK != Sema::TUK_Definition)) { if (DS.getTypeSpecType() != DeclSpec::TST_error) { @@ -1950,6 +1941,14 @@ } } + // If this is an elaborated type specifier, and we delayed + // diagnostics before, just merge them into the current pool. + if (shouldDelayDiagsInTag) { + diagsFromTag.done(); + if (TUK == Sema::TUK_Reference) + diagsFromTag.redelay(); + } + // If there is a body, parse it and inform the actions module. if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -259,6 +259,19 @@ return nullptr; } + // Turn off usual access checking for templates. + // Remove them from the pool of delayed diagnostics. + // We don't use `SuppressAccessChecks` here because + // it suppresses ALL the kinds of diagnostics, + // but we need to keep some of them. + // For instance marked as unavailable: + // `class __attribute((unavailable)) UnavailableClass;` + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { + if (sema::DelayedDiagnosticPool *Pool = + getActions().DelayedDiagnostics.getCurrentPool()) + Pool->removeAllOfKind(sema::DelayedDiagnostic::DDKind::Access); + } + llvm::TimeTraceScope TimeScope("ParseTemplate", [&]() { return std::string(DeclaratorInfo.getIdentifier() != nullptr ? DeclaratorInfo.getIdentifier()->getName() diff --git a/clang/test/CXX/class.access/class.friend/p1.cpp b/clang/test/CXX/class.access/class.friend/p1.cpp --- a/clang/test/CXX/class.access/class.friend/p1.cpp +++ b/clang/test/CXX/class.access/class.friend/p1.cpp @@ -273,7 +273,7 @@ // Return types, parameters and default arguments to friend functions. namespace test8 { class A { - typedef int I; // expected-note 4 {{declared private here}} + typedef int I; // expected-note 7 {{declared private here}} static const I x = 0; // expected-note {{implicitly declared private here}} friend I f(I i); template friend I g(I i); @@ -287,10 +287,19 @@ template A::I g(A::I i); A::I f2(A::I i = A::x) {} // expected-error 3 {{is a private member of}} - template A::I g2(A::I i) { // expected-error 2 {{is a private member of}} + template A::I g2(A::I i) { // expected-error {{is a private member of}} T t; } + template <> A::I g2(A::I i) { return 0; } // expected-error {{is a private member of}} template A::I g2(A::I i); + template <> A::I g2(A::I i); // expected-error {{is a private member of}} + template <> A::I g2(A::I i); // expected-error {{is a private member of}} + template A::I g2(A::I i); // OK + template int g2(int i); // OK + template A::I g2(A::I i); // OK + + template A::I g3(A::I i) { return 0; } // expected-error {{is a private member of}} + template <> int g3(int i); // OK } // PR6885 diff --git a/clang/test/CXX/drs/dr1xx.cpp b/clang/test/CXX/drs/dr1xx.cpp --- a/clang/test/CXX/drs/dr1xx.cpp +++ b/clang/test/CXX/drs/dr1xx.cpp @@ -934,12 +934,12 @@ template void C::g() {} class A { - class B {}; // expected-note {{here}} + class B {}; void f(); }; template void C::f(); - template <> void C::g(); // expected-error {{private}} + template <> void C::g(); void A::f() { C cb; diff --git a/clang/test/CXX/temp/temp.spec/func.spec.cpp b/clang/test/CXX/temp/temp.spec/func.spec.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CXX/temp/temp.spec/func.spec.cpp @@ -0,0 +1,144 @@ +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s + +// C++20 [temp.explicit] 17.8/6: +// The usual access checking rules do not apply to names in a declaration +// of an explicit instantiation or explicit specialization, with +// the exception of names appearing in a function body, default argument, +// base-clause, member-specification, enumerator-list, or static data member +// or variable template initializer. + +class A { + // expected-note@+1 14{{implicitly declared private here}} + template class B {}; + // expected-note@+1 {{implicitly declared private here}} + static constexpr int num1 = 42; + +protected: + // expected-note@+1 9{{declared protected here}} + class C {}; + // expected-note@+1 {{declared protected here}} + static constexpr int num2 = 43; + static int num4; + +public: + template class D {}; + static constexpr int num3 = 44; +}; +int A::num4 = 44; + +class E : public A { + template A::C func1(); + // expected-error@+1 {{is a private member of}} + template A::B func2(); + template A::D func3(); + // expected-error@+1 {{is a private member of}} + template class A::B func4(); + template void func5(); + + template <> A::C func1(); + // expected-error@+1 {{is a private member of}} + template <> A::B func2(); + template <> A::D func3(); + // expected-error@+1 {{is a private member of}} + template <> class A::B func4(); + template <> void func5(); + // expected-error@+1 {{is a private member of}} + template <> void func5>(); + template <> void func5>(); + template <> void func5(); +}; + +template class StealClass { + friend int stealFunc() { return *x; } +}; + +template class StealClass<&A::num4>; +int stealFunc(); + +int stealFunc2() { + return stealFunc(); +} + +//----------------------------------------------------------// + +// forward declarations + +// expected-error@+1 {{is a protected member of}} +template A::C func1(); +// expected-error@+1 {{is a private member of}} +template A::B func2(); +template A::D func3(); +// expected-error@+1 {{is a private member of}} +template class A::B func4(); +template void func5(); +// expected-error@+1 {{is a private member of}} +template void func6(); +// expected-error@+1 {{is a protected member of}} +template void func7(); +template void func8(int x = sizeof(A::C)); +template void func9(int x = A::num1); +template void func10(A::B, int x = A::num2); +template void func11(A::C, A::D, int = A::num3); + +//----------------------------------------------------------// + +// definitions + +// expected-error@+1 2{{is a protected member of}} +template A::C func1() { A::C x; } +// expected-error@+2 {{is a private member of}} +// expected-error@+1 {{is a protected member of}} +template A::B func2() { A::D x; } +template A::D func3() { A::D x; } +// expected-error@+2 2{{is a private member of}} +// expected-error@+1 {{is a protected member of}} +template class A::B func4() { A::B x; } template void func5() { + // expected-error@+2 {{is a private member of}} + // expected-error@+1 {{is a protected member of}} + A::B> x; + // expected-error@+1 {{is a private member of}} + A::B x2; +} +template void func8(int x) {} +template void func9(int x) {} +template void func10(A::B, int x) {} +template void func11(A::C, A::D, int) {} +template void func12() {} +template void func13() {} +template void func14() {} +template