Implement the restrictions in C++ [class.friend]p6, which disallow

defining a friend function with a qualified name or in a local
class. Fixes PR9853. 

llvm-svn: 141524
This commit is contained in:
Douglas Gregor 2011-10-10 01:11:59 +00:00
parent b60187ae74
commit 16e65616d6
3 changed files with 58 additions and 3 deletions

View File

@ -637,6 +637,10 @@ def err_no_matching_local_friend_suggest : Error<
"no matching function %0 found in local scope; did you mean %2">;
def err_partial_specialization_friend : Error<
"partial specialization cannot be declared as a friend">;
def err_qualified_friend_def : Error<
"friend function definition cannot be qualified with '%0'">;
def err_friend_def_in_local_class : Error<
"friend function cannot be defined in a local class">;
def err_abstract_type_in_decl : Error<
"%select{return|parameter|variable|field}0 type %1 is an abstract class">;

View File

@ -10196,6 +10196,14 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
DCScope = getScopeForDeclContext(S, DC);
// C++ [class.friend]p6:
// A function can be defined in a friend declaration of a class if and
// only if the class is a non-local class (9.8), the function name is
// unqualified, and the function has namespace scope.
if (isLocal && IsDefinition) {
Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
}
// - There's a non-dependent scope specifier, in which case we
// compute it and do a previous lookup there for a function
// or function template.
@ -10230,12 +10238,35 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
if (DC->Equals(CurContext))
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
if (IsDefinition) {
// C++ [class.friend]p6:
// A function can be defined in a friend declaration of a class if and
// only if the class is a non-local class (9.8), the function name is
// unqualified, and the function has namespace scope.
SemaDiagnosticBuilder DB
= Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
DB << SS.getScopeRep();
if (DC->isFileContext())
DB << FixItHint::CreateRemoval(SS.getRange());
SS.clear();
}
// - There's a scope specifier that does not match any template
// parameter lists, in which case we use some arbitrary context,
// create a method or method template, and wait for instantiation.
// - There's a scope specifier that does match some template
// parameter lists, which we don't handle right now.
} else {
if (IsDefinition) {
// C++ [class.friend]p6:
// A function can be defined in a friend declaration of a class if and
// only if the class is a non-local class (9.8), the function name is
// unqualified, and the function has namespace scope.
Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
<< SS.getScopeRep();
}
DC = CurContext;
assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
}

View File

@ -0,0 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
void f1();
struct X {
void f2();
};
struct Y {
friend void ::f1() { } // expected-error{{friend function definition cannot be qualified with '::'}}
friend void X::f2() { } // expected-error{{friend function definition cannot be qualified with 'X::'}}
};
void local() {
void f();
struct Local {
friend void f() { } // expected-error{{friend function cannot be defined in a local class}}
};
}