summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-10-10 01:11:59 +0000
committerDouglas Gregor <dgregor@apple.com>2011-10-10 01:11:59 +0000
commit16e65616d64b206e89a656ae49b7e7fed3f7e0ce (patch)
tree2542ba3533cdeb87495ec5114511b0e5e680235a /clang
parentb60187ae74d1c326352315d9561ebf0162d48c2a (diff)
downloadbcm5719-llvm-16e65616d64b206e89a656ae49b7e7fed3f7e0ce.tar.gz
bcm5719-llvm-16e65616d64b206e89a656ae49b7e7fed3f7e0ce.zip
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
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp35
-rw-r--r--clang/test/CXX/class.access/class.friend/p6.cpp20
3 files changed, 58 insertions, 3 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8356340a224..c4e0168ce7c 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 031afa078da..b16cbb80c40 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<CXXRecordDecl>(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 00000000000..7f7d9099032
--- /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}}
+ };
+}
OpenPOWER on IntegriCloud