зеркало из https://github.com/microsoft/clang-1.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116661 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
b10ce9f4fc
Коммит
6102ca1d49
|
@ -48,6 +48,11 @@ private:
|
||||||
// Location of the 'friend' specifier.
|
// Location of the 'friend' specifier.
|
||||||
SourceLocation FriendLoc;
|
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::friend_iterator;
|
||||||
friend class CXXRecordDecl;
|
friend class CXXRecordDecl;
|
||||||
|
|
||||||
|
@ -56,7 +61,8 @@ private:
|
||||||
: Decl(Decl::Friend, DC, L),
|
: Decl(Decl::Friend, DC, L),
|
||||||
Friend(Friend),
|
Friend(Friend),
|
||||||
NextFriend(0),
|
NextFriend(0),
|
||||||
FriendLoc(FriendL) {
|
FriendLoc(FriendL),
|
||||||
|
UnsupportedFriend(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit FriendDecl(EmptyShell Empty)
|
explicit FriendDecl(EmptyShell Empty)
|
||||||
|
@ -87,6 +93,14 @@ public:
|
||||||
return FriendLoc;
|
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.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
static bool classof(const FriendDecl *D) { return true; }
|
static bool classof(const FriendDecl *D) { return true; }
|
||||||
|
|
|
@ -516,8 +516,9 @@ static AccessResult MatchesFriend(Sema &S,
|
||||||
static AccessResult MatchesFriend(Sema &S,
|
static AccessResult MatchesFriend(Sema &S,
|
||||||
const EffectiveContext &EC,
|
const EffectiveContext &EC,
|
||||||
FriendDecl *FriendD) {
|
FriendDecl *FriendD) {
|
||||||
// Whitelist accesses if there's an invalid friend declaration.
|
// Whitelist accesses if there's an invalid or unsupported friend
|
||||||
if (FriendD->isInvalidDecl())
|
// declaration.
|
||||||
|
if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())
|
||||||
return AR_accessible;
|
return AR_accessible;
|
||||||
|
|
||||||
if (TypeSourceInfo *T = FriendD->getFriendType())
|
if (TypeSourceInfo *T = FriendD->getFriendType())
|
||||||
|
|
|
@ -3410,11 +3410,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||||
= MatchTemplateParametersToScopeSpecifier(
|
= MatchTemplateParametersToScopeSpecifier(
|
||||||
D.getDeclSpec().getSourceRange().getBegin(),
|
D.getDeclSpec().getSourceRange().getBegin(),
|
||||||
D.getCXXScopeSpec(),
|
D.getCXXScopeSpec(),
|
||||||
(TemplateParameterList**)TemplateParamLists.get(),
|
TemplateParamLists.get(),
|
||||||
TemplateParamLists.size(),
|
TemplateParamLists.size(),
|
||||||
isFriend,
|
isFriend,
|
||||||
isExplicitSpecialization,
|
isExplicitSpecialization,
|
||||||
Invalid)) {
|
Invalid)) {
|
||||||
// All but one template parameter lists have been matching.
|
// All but one template parameter lists have been matching.
|
||||||
--NumMatchedTemplateParamLists;
|
--NumMatchedTemplateParamLists;
|
||||||
|
|
||||||
|
@ -3462,7 +3462,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||||
if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
|
if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
|
||||||
NewFD->setTemplateParameterListsInfo(Context,
|
NewFD->setTemplateParameterListsInfo(Context,
|
||||||
NumMatchedTemplateParamLists,
|
NumMatchedTemplateParamLists,
|
||||||
(TemplateParameterList**)TemplateParamLists.release());
|
TemplateParamLists.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Invalid) {
|
if (Invalid) {
|
||||||
|
@ -3732,14 +3732,20 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||||
|
|
||||||
// Qualified decls generally require a previous declaration.
|
// Qualified decls generally require a previous declaration.
|
||||||
if (D.getCXXScopeSpec().isSet()) {
|
if (D.getCXXScopeSpec().isSet()) {
|
||||||
// ...with the major exception of dependent friend declarations.
|
// ...with the major exception of templated-scope or
|
||||||
// In theory, this condition could be whether the qualifier
|
// dependent-scope friend declarations.
|
||||||
// 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()) {
|
|
||||||
// ignore these
|
|
||||||
|
|
||||||
|
// 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 {
|
} else {
|
||||||
// The user tried to provide an out-of-line definition for a
|
// The user tried to provide an out-of-line definition for a
|
||||||
// function that is a member of a class or namespace, but there
|
// function that is a member of a class or namespace, but there
|
||||||
|
|
|
@ -6532,6 +6532,17 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
|
||||||
|
|
||||||
if (ND->isInvalidDecl())
|
if (ND->isInvalidDecl())
|
||||||
FrD->setInvalidDecl();
|
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;
|
return ND;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1375,13 +1375,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
||||||
// If there were at least as many template-ids as there were template
|
// If there were at least as many template-ids as there were template
|
||||||
// parameter lists, then there are no template parameter lists remaining for
|
// parameter lists, then there are no template parameter lists remaining for
|
||||||
// the declaration itself.
|
// the declaration itself.
|
||||||
if (Idx >= NumParamLists) {
|
if (Idx >= NumParamLists)
|
||||||
// Silently drop template member friend declarations.
|
|
||||||
// TODO: implement these
|
|
||||||
if (IsFriend && NumParamLists) Invalid = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
// If there were too many template parameter lists, complain about that now.
|
// If there were too many template parameter lists, complain about that now.
|
||||||
if (Idx != NumParamLists - 1) {
|
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
|
// Return the last template parameter list, which corresponds to the
|
||||||
// entity being declared.
|
// entity being declared.
|
||||||
return ParamLists[NumParamLists - 1];
|
return ParamLists[NumParamLists - 1];
|
||||||
|
|
|
@ -908,6 +908,7 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
|
||||||
else
|
else
|
||||||
D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
|
D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
|
||||||
D->NextFriend = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
|
D->NextFriend = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
|
||||||
|
D->UnsupportedFriend = (Record[Idx++] != 0);
|
||||||
D->FriendLoc = ReadSourceLocation(Record, Idx);
|
D->FriendLoc = ReadSourceLocation(Record, Idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -835,6 +835,7 @@ void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
|
||||||
else
|
else
|
||||||
Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record);
|
Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record);
|
||||||
Writer.AddDeclRef(D->NextFriend, Record);
|
Writer.AddDeclRef(D->NextFriend, Record);
|
||||||
|
Record.push_back(D->UnsupportedFriend);
|
||||||
Writer.AddSourceLocation(D->FriendLoc, Record);
|
Writer.AddSourceLocation(D->FriendLoc, Record);
|
||||||
Code = serialization::DECL_FRIEND;
|
Code = serialization::DECL_FRIEND;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,3 +92,20 @@ namespace test3 {
|
||||||
// don't have key functions.
|
// don't have key functions.
|
||||||
template void S<int>::m();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче