aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclFriend.h16
-rw-r--r--lib/Sema/SemaAccess.cpp5
-rw-r--r--lib/Sema/SemaDecl.cpp32
-rw-r--r--lib/Sema/SemaDeclCXX.cpp11
-rw-r--r--lib/Sema/SemaTemplate.cpp12
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp1
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp17
8 files changed, 68 insertions, 27 deletions
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 4b5e6fd48b..10befe0831 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -48,6 +48,11 @@ private:
// Location of the 'friend' specifier.
SourceLocation FriendLoc;
+ /// True if this 'friend' declaration is unsupported. Eventually we
+ /// will support every possible friend declaration, but for now we
+ /// silently ignore some and set this flag to authorize all access.
+ bool UnsupportedFriend;
+
friend class CXXRecordDecl::friend_iterator;
friend class CXXRecordDecl;
@@ -56,7 +61,8 @@ private:
: Decl(Decl::Friend, DC, L),
Friend(Friend),
NextFriend(0),
- FriendLoc(FriendL) {
+ FriendLoc(FriendL),
+ UnsupportedFriend(false) {
}
explicit FriendDecl(EmptyShell Empty)
@@ -87,6 +93,14 @@ public:
return FriendLoc;
}
+ /// Determines if this friend kind is unsupported.
+ bool isUnsupportedFriend() const {
+ return UnsupportedFriend;
+ }
+ void setUnsupportedFriend(bool Unsupported) {
+ UnsupportedFriend = Unsupported;
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FriendDecl *D) { return true; }
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index ea6481bd8a..c3a1e75210 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -516,8 +516,9 @@ static AccessResult MatchesFriend(Sema &S,
static AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC,
FriendDecl *FriendD) {
- // Whitelist accesses if there's an invalid friend declaration.
- if (FriendD->isInvalidDecl())
+ // Whitelist accesses if there's an invalid or unsupported friend
+ // declaration.
+ if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())
return AR_accessible;
if (TypeSourceInfo *T = FriendD->getFriendType())
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e7714521c8..d11819461e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3410,11 +3410,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
= MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getSourceRange().getBegin(),
D.getCXXScopeSpec(),
- (TemplateParameterList**)TemplateParamLists.get(),
- TemplateParamLists.size(),
- isFriend,
- isExplicitSpecialization,
- Invalid)) {
+ TemplateParamLists.get(),
+ TemplateParamLists.size(),
+ isFriend,
+ isExplicitSpecialization,
+ Invalid)) {
// All but one template parameter lists have been matching.
--NumMatchedTemplateParamLists;
@@ -3462,7 +3462,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
NewFD->setTemplateParameterListsInfo(Context,
NumMatchedTemplateParamLists,
- (TemplateParameterList**)TemplateParamLists.release());
+ TemplateParamLists.release());
}
if (Invalid) {
@@ -3732,14 +3732,20 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Qualified decls generally require a previous declaration.
if (D.getCXXScopeSpec().isSet()) {
- // ...with the major exception of dependent friend declarations.
- // In theory, this condition could be whether the qualifier
- // is dependent; in practice, the way we nest template parameters
- // prevents this sort of matching from working, so we have to base it
- // on the general dependence of the context.
- if (isFriend && CurContext->isDependentContext()) {
+ // ...with the major exception of templated-scope or
+ // dependent-scope friend declarations.
+
+ // TODO: we currently also suppress this check in dependent
+ // contexts because (1) the parameter depth will be off when
+ // matching friend templates and (2) we might actually be
+ // selecting a friend based on a dependent factor. But there
+ // are situations where these conditions don't apply and we
+ // can actually do this check immediately.
+ if (isFriend &&
+ (NumMatchedTemplateParamLists ||
+ D.getCXXScopeSpec().getScopeRep()->isDependent() ||
+ CurContext->isDependentContext())) {
// ignore these
-
} else {
// The user tried to provide an out-of-line definition for a
// function that is a member of a class or namespace, but there
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index be1ee358e2..583f7c59b4 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -6532,6 +6532,17 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
if (ND->isInvalidDecl())
FrD->setInvalidDecl();
+ else {
+ FunctionDecl *FD;
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+ FD = FTD->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(ND);
+
+ // Mark templated-scope function declarations as unsupported.
+ if (FD->getNumTemplateParameterLists())
+ FrD->setUnsupportedFriend(true);
+ }
return ND;
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f85c3f0070..66ded48c24 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1375,13 +1375,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// If there were at least as many template-ids as there were template
// parameter lists, then there are no template parameter lists remaining for
// the declaration itself.
- if (Idx >= NumParamLists) {
- // Silently drop template member friend declarations.
- // TODO: implement these
- if (IsFriend && NumParamLists) Invalid = true;
-
+ if (Idx >= NumParamLists)
return 0;
- }
// If there were too many template parameter lists, complain about that now.
if (Idx != NumParamLists - 1) {
@@ -1410,11 +1405,6 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
}
}
- // Silently drop template member template friend declarations.
- // TODO: implement these
- if (IsFriend && NumParamLists > 1)
- Invalid = true;
-
// Return the last template parameter list, which corresponds to the
// entity being declared.
return ParamLists[NumParamLists - 1];
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index c89273567e..05ade63719 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -908,6 +908,7 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
else
D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
D->NextFriend = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
+ D->UnsupportedFriend = (Record[Idx++] != 0);
D->FriendLoc = ReadSourceLocation(Record, Idx);
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 0dcc822fbc..bf7c259635 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -835,6 +835,7 @@ void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
else
Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record);
Writer.AddDeclRef(D->NextFriend, Record);
+ Record.push_back(D->UnsupportedFriend);
Writer.AddSourceLocation(D->FriendLoc, Record);
Code = serialization::DECL_FRIEND;
}
diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp
index 47ff16b8a6..a8729035e2 100644
--- a/test/CodeGenCXX/template-instantiation.cpp
+++ b/test/CodeGenCXX/template-instantiation.cpp
@@ -92,3 +92,20 @@ namespace test3 {
// don't have key functions.
template void S<int>::m();
}
+
+namespace test4 {
+ template <class T> struct A { static void foo(); };
+
+ class B {
+ template <class T> friend void A<T>::foo();
+ B();
+ };
+
+ template <class T> void A<T>::foo() {
+ B b;
+ }
+
+ unsigned test() {
+ A<int>::foo();
+ }
+}