diff options
-rw-r--r-- | include/clang/Parse/Action.h | 10 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 22 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 6 | ||||
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 15 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.explicit/p11.cpp | 18 |
6 files changed, 73 insertions, 2 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index d8bb8a5b61..fed4361f1a 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -2278,6 +2278,16 @@ public: return TypeResult(); } + /// \brief Called when the parser begins parsing a construct which should not + /// have access control applied to it. + virtual void ActOnStartSuppressingAccessChecks() { + } + + /// \brief Called when the parser finishes parsing a construct which should + /// not have access control applied to it. + virtual void ActOnStopSuppressingAccessChecks() { + } + //===----------------------- Obj-C Declarations -------------------------===// // ActOnStartClassInterface - this action is called immediately after parsing diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 53fc3405bb..ffef288e71 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -613,6 +613,20 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ConsumeCodeCompletionToken(); } + // C++03 [temp.explicit] 14.7.2/8: + // The usual access checking rules do not apply to names used to specify + // explicit instantiations. + // + // As an extension we do not perform access checking on the names used to + // specify explicit specializations either. This is important to allow + // specializing traits classes for private types. + bool SuppressingAccessChecks = false; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) { + Actions.ActOnStartSuppressingAccessChecks(); + SuppressingAccessChecks = true; + } + AttributeList *AttrList = 0; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) @@ -732,10 +746,18 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, DS.SetTypeSpecError(); SkipUntil(tok::semi, false, true); TemplateId->Destroy(); + if (SuppressingAccessChecks) + Actions.ActOnStopSuppressingAccessChecks(); + return; } } + // As soon as we're finished parsing the class's template-id, turn access + // checking back on. + if (SuppressingAccessChecks) + Actions.ActOnStopSuppressingAccessChecks(); + // There are four options here. If we have 'struct foo;', then this // is either a forward declaration or a friend declaration, which // have to be treated differently. If we have 'struct foo {...' or diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index eadc2ad253..d520a78abe 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -125,8 +125,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), - NumSFINAEErrors(0), NonInstantiationEntries(0), - CurrentInstantiationScope(0), TyposCorrected(0), + NumSFINAEErrors(0), SuppressAccessChecking(false), + NonInstantiationEntries(0), CurrentInstantiationScope(0), TyposCorrected(0), AnalysisWarnings(*this) { TUScope = 0; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 9d5e290b2f..fcf5e94149 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2797,6 +2797,12 @@ public: void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx); + /// A flag to suppress access checking. + bool SuppressAccessChecking; + + void ActOnStartSuppressingAccessChecks(); + void ActOnStopSuppressingAccessChecks(); + enum AbstractDiagSelID { AbstractNone = -1, AbstractReturnType, diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 7845f6d0a9..e110e3dfa4 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1024,6 +1024,9 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, if (Entity.getAccess() == AS_public) return Sema::AR_accessible; + if (S.SuppressAccessChecking) + return Sema::AR_accessible; + // If we're currently parsing a top-level declaration, delay // diagnostics. This is the only case where parsing a declaration // can actually change our effective context for the purposes of @@ -1334,3 +1337,15 @@ void Sema::CheckLookupAccess(const LookupResult &R) { } } } + +void Sema::ActOnStartSuppressingAccessChecks() { + assert(!SuppressAccessChecking && + "Tried to start access check suppression when already started."); + SuppressAccessChecking = true; +} + +void Sema::ActOnStopSuppressingAccessChecks() { + assert(SuppressAccessChecking && + "Tried to stop access check suprression when already stopped."); + SuppressAccessChecking = false; +} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p11.cpp b/test/CXX/temp/temp.spec/temp.explicit/p11.cpp new file mode 100644 index 0000000000..4ca5428315 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p11.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +class X { + template <typename T> class Y {}; +}; + +class A { + class B {}; + class C {}; +}; + +// C++0x [temp.explicit] 14.7.2/11: +// The usual access checking rules do not apply to names used to specify +// explicit instantiations. +template class X::Y<A::B>; + +// As an extension, this rule is applied to explicit specializations as well. +template <> class X::Y<A::C> {}; |