"out-of-line definition of %0 from class %1 without definition">;
def err_member_def_does_not_match : Error<
"out-of-line definition of %0 does not match any declaration in %1">;
+def err_friend_decl_with_def_arg_must_be_def : Error<
+ "friend declaration specifying a default argument must be a definition">;
+def err_friend_decl_with_def_arg_redeclared : Error<
+ "friend declaration specifying a default argument must be the only declaration">;
def err_friend_decl_does_not_match : Error<
"friend declaration of %0 does not match any declaration in %1">;
def err_member_def_does_not_match_suggest : Error<
}
}
+static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) {
+ for (unsigned NumParams = FD->getNumParams(); NumParams > 0; --NumParams) {
+ const ParmVarDecl *PVD = FD->getParamDecl(NumParams-1);
+ if (!PVD->hasDefaultArg())
+ return false;
+ if (!PVD->hasInheritedDefaultArg())
+ return true;
+ }
+ return false;
+}
+
/// MergeCXXFunctionDecl - Merge two declarations of the same C++
/// function, once we already know that they have the same
/// type. Subroutine of MergeFunctionDecl. Returns true if there was an
Invalid = true;
}
+ // C++11 [dcl.fct.default]p4: If a friend declaration specifies a default
+ // argument expression, that declaration shall be a deļ¬nition and shall be
+ // the only declaration of the function or function template in the
+ // translation unit.
+ if (Old->getFriendObjectKind() == Decl::FOK_Undeclared &&
+ functionDeclHasDefaultArgument(Old)) {
+ Diag(New->getLocation(), diag::err_friend_decl_with_def_arg_redeclared);
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ Invalid = true;
+ }
+
if (CheckEquivalentExceptionSpec(Old, New))
Invalid = true;
else
FD = cast<FunctionDecl>(ND);
+ // C++11 [dcl.fct.default]p4: If a friend declaration specifies a
+ // default argument expression, that declaration shall be a definition
+ // and shall be the only declaration of the function or function
+ // template in the translation unit.
+ if (functionDeclHasDefaultArgument(FD)) {
+ if (FunctionDecl *OldFD = FD->getPreviousDecl()) {
+ Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_redeclared);
+ Diag(OldFD->getLocation(), diag::note_previous_declaration);
+ } else if (!D.isFunctionDefinition())
+ Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_must_be_def);
+ }
+
// Mark templated-scope function declarations as unsupported.
if (FD->getNumTemplateParameterLists())
FrD->setUnsupportedFriend(true);
};
}
-namespace dr136 { // dr136: no
- void f(int, int, int = 0);
- void g(int, int, int);
+namespace dr136 { // dr136: 3.4
+ void f(int, int, int = 0); // expected-note {{previous declaration is here}}
+ void g(int, int, int); // expected-note {{previous declaration is here}}
struct A {
- // FIXME: These declarations of f, g, and h are invalid.
- friend void f(int, int = 0, int);
- friend void g(int, int, int = 0);
- friend void h(int, int, int = 0);
- friend void i(int, int, int = 0) {}
+ friend void f(int, int = 0, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ friend void g(int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ friend void h(int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be a definition}}
+ friend void i(int, int, int = 0) {} // expected-note {{previous declaration is here}}
friend void j(int, int, int = 0) {}
operator int();
};
- // FIXME: This declaration of i is invalid.
- void i(int, int, int);
+ void i(int, int, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
void q() {
j(A(), A()); // ok, has default argument
}
- // FIXME: Also test extern "C" friends and default arguments from other
- // namespaces?
+ extern "C" void k(int, int, int, int); // expected-note {{previous declaration is here}}
+ namespace NSA {
+ struct A {
+ friend void dr136::k(int, int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}} \
+ // expected-note {{previous declaration is here}}
+ };
+ }
+ namespace NSB {
+ struct A {
+ friend void dr136::k(int, int, int = 0, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ };
+ }
+ struct B {
+ void f(int); // expected-note {{previous declaration is here}}
+ };
+ struct C {
+ friend void B::f(int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ };
}
namespace dr137 { // dr137: yes
namespace nm {
struct str {
- friend int foo(int arg = 0);
+ friend void foo(int arg = 0) {};
};
}
// PR5134
namespace test3 {
class Foo {
- friend const int getInt(int inInt = 0);
+ friend const int getInt(int inInt = 0) {}
};
}
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#136">136</a></td>
<td>CD1</td>
<td>Default arguments and friend declarations</td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#137">137</a></td>