diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8356340a2244..c4e0168ce7cc 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -637,7 +637,11 @@ 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">; def err_allocation_of_abstract_type : Error< diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 031afa078dac..b16cbb80c40c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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. @@ -10229,6 +10237,20 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, // class that is not a member of the class . . . 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, @@ -10236,10 +10258,19 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, // - 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(DC) && "friend declaration not in class?"); } - + if (!DC->isRecord()) { // This implies that it has to be an operator or function. if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName || @@ -10251,7 +10282,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, return 0; } } - + bool Redeclaration = false; bool AddToScope = true; NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous, diff --git a/clang/test/CXX/class.access/class.friend/p6.cpp b/clang/test/CXX/class.access/class.friend/p6.cpp new file mode 100644 index 000000000000..7f7d90990328 --- /dev/null +++ b/clang/test/CXX/class.access/class.friend/p6.cpp @@ -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}} + }; +}