summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-10-16 06:59:13 +0000
committerJohn McCall <rjmccall@apple.com>2010-10-16 06:59:13 +0000
commit2c2eb12d9c895b2174788f5068f106e5e933bbfc (patch)
treedb885535fc5fa507a44cee8d9783717cf82fa1d3
parent622581b73bf9466eaa79deb336613e42eef7d68d (diff)
downloadbcm5719-llvm-2c2eb12d9c895b2174788f5068f106e5e933bbfc.tar.gz
bcm5719-llvm-2c2eb12d9c895b2174788f5068f106e5e933bbfc.zip
White-listing templated-scope friend decls is a good idea, but doing it
by marking the decl invalid isn't. Make some steps towards supporting these and then hastily shut them down at the last second by marking them as unsupported. llvm-svn: 116661
-rw-r--r--clang/include/clang/AST/DeclFriend.h16
-rw-r--r--clang/lib/Sema/SemaAccess.cpp5
-rw-r--r--clang/lib/Sema/SemaDecl.cpp32
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp11
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp12
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp1
-rw-r--r--clang/test/CodeGenCXX/template-instantiation.cpp17
8 files changed, 68 insertions, 27 deletions
diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h
index 4b5e6fd48bb..10befe08316 100644
--- a/clang/include/clang/AST/DeclFriend.h
+++ b/clang/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/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index ea6481bd8ab..c3a1e752105 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e7714521c84..d11819461ec 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index be1ee358e2a..583f7c59b41 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f85c3f00709..66ded48c240 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/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/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index c89273567e5..05ade637195 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/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/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 0dcc822fbc9..bf7c259635f 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/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/clang/test/CodeGenCXX/template-instantiation.cpp b/clang/test/CodeGenCXX/template-instantiation.cpp
index 47ff16b8a62..a8729035e28 100644
--- a/clang/test/CodeGenCXX/template-instantiation.cpp
+++ b/clang/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();
+ }
+}
OpenPOWER on IntegriCloud