aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Parse/Action.h10
-rw-r--r--lib/Parse/ParseDeclCXX.cpp22
-rw-r--r--lib/Sema/Sema.cpp4
-rw-r--r--lib/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaAccess.cpp15
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p11.cpp18
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> {};