aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/SemaAccess.cpp18
-rw-r--r--lib/Sema/SemaDecl.cpp10
-rw-r--r--lib/Sema/SemaTemplate.cpp15
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp6
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp2
6 files changed, 37 insertions, 16 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index efe75e9b08..c563d11643 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1256,6 +1256,8 @@ def err_template_spec_decl_function_scope : Error<
"explicit specialization of %0 in function scope">;
def err_template_spec_decl_class_scope : Error<
"explicit specialization of %0 in class scope">;
+def err_template_spec_decl_friend : Error<
+ "cannot declare an explicit specialization in a friend">;
def err_template_spec_decl_out_of_scope_global : Error<
"%select{class template|class template partial|function template|member "
"function|static data member|member class}0 specialization of %1 must "
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index e74c8f60c3..5b1a9d880a 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -53,10 +53,11 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
namespace {
struct EffectiveContext {
- EffectiveContext() : Function(0), Dependent(false) {}
+ EffectiveContext() : Inner(0), Function(0), Dependent(false) {}
- explicit EffectiveContext(DeclContext *DC) {
- Dependent = DC->isDependentContext();
+ explicit EffectiveContext(DeclContext *DC)
+ : Inner(DC),
+ Dependent(DC->isDependentContext()) {
if (isa<FunctionDecl>(DC)) {
Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
@@ -86,14 +87,15 @@ struct EffectiveContext {
!= Records.end();
}
- DeclContext *getPrimaryContext() const {
- assert((Function || !Records.empty()) && "context has no primary context");
- if (Function) return Function;
- return Records[0];
+ /// Retrieves the innermost "useful" context. Can be null if we're
+ /// doing access-control without privileges.
+ DeclContext *getInnerContext() const {
+ return Inner;
}
typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
+ DeclContext *Inner;
llvm::SmallVector<CXXRecordDecl*, 4> Records;
FunctionDecl *Function;
bool Dependent;
@@ -636,7 +638,7 @@ static void DelayAccess(Sema &S,
SourceLocation Loc,
const Sema::AccessedEntity &Entity) {
assert(EC.isDependent() && "delaying non-dependent access");
- DeclContext *DC = EC.getPrimaryContext();
+ DeclContext *DC = EC.getInnerContext();
assert(DC->isDependentContext() && "delaying non-dependent access");
DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
Loc,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index bf92ef829b..1435a8f721 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2918,6 +2918,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else {
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
+
+ // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);".
+ if (isFriend && isFunctionTemplateSpecialization) {
+ SourceRange Range = TemplateParams->getSourceRange();
+ Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend)
+ << Name << Range << CodeModificationHint::CreateRemoval(Range);
+ }
}
// FIXME: Free this memory properly.
@@ -3101,6 +3108,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.getDeclSpec().getSourceRange().getBegin(),
"template<> ");
isFunctionTemplateSpecialization = true;
+ } else {
+ // "friend void foo<>(int);" is an implicit specialization decl.
+ isFunctionTemplateSpecialization = true;
}
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index abe9363352..504b513b2c 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3961,9 +3961,14 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
+
+ // If this is a friend declaration, then we're not really declaring
+ // an explicit specialization.
+ bool isFriend = (FD->getFriendObjectKind() != Decl::FOK_None);
// Check the scope of this explicit specialization.
- if (CheckTemplateSpecializationScope(*this,
+ if (!isFriend &&
+ CheckTemplateSpecializationScope(*this,
Specialization->getPrimaryTemplate(),
Specialization, FD->getLocation(),
false))
@@ -3980,7 +3985,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
assert(SpecInfo && "Function template specialization info missing?");
bool SuppressNew = false;
- if (CheckSpecializationInstantiationRedecl(FD->getLocation(),
+ if (!isFriend &&
+ CheckSpecializationInstantiationRedecl(FD->getLocation(),
TSK_ExplicitSpecialization,
Specialization,
SpecInfo->getTemplateSpecializationKind(),
@@ -3990,7 +3996,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
- SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
+ if (!isFriend)
+ SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
// Turn the given function declaration into a function template
// specialization, with the template arguments from the previous
@@ -3999,7 +4006,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
new (Context) TemplateArgumentList(
*Specialization->getTemplateSpecializationArgs()),
/*InsertPos=*/0,
- TSK_ExplicitSpecialization);
+ SpecInfo->getTemplateSpecializationKind());
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
index 69ce5a077d..0f18e76f52 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -95,7 +95,7 @@ namespace test3 {
friend class User<bool>;
friend bool transform<>(Bool, bool);
- bool value; // expected-note {{declared private here}}
+ bool value; // expected-note 2 {{declared private here}}
};
template <class T> class User {
@@ -105,13 +105,13 @@ namespace test3 {
};
template <class T> T transform(Bool b, T value) {
- if (b.value)
+ if (b.value) // expected-error {{'value' is a private member of 'test3::Bool'}}
return value;
return value + 1;
}
template bool transform(Bool, bool);
- template int transform(Bool, int);
+ template int transform(Bool, int); // expected-note {{requested here}}
template class User<bool>;
template class User<int>; // expected-note {{requested here}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
index f987c120a2..86cdcf80cb 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
@@ -6,7 +6,7 @@ template<typename T>
struct A { };
struct X {
- template<> friend void f<int>(int); // expected-error{{in class scope}}
+ template<> friend void f<int>(int); // expected-error{{in a friend}}
template<> friend class A<int>; // expected-error{{cannot be a friend}}
friend void f<float>(float); // okay