This matches MSVC's logic, which seems to be that when the friend
declaration is qualified, it cannot be a declaration of a new symbol
and so the dll linkage doesn't change.
Differential Revision: http://reviews.llvm.org/D4764
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@214774
91177308-0d34-0410-b5e6-
96231b3b80d8
}
// A redeclaration is not allowed to drop a dllimport attribute, the only
- // exceptions being inline function definitions and local extern declarations.
+ // exceptions being inline function definitions, local extern declarations,
+ // and qualified friend declarations.
// NB: MSVC converts such a declaration to dllexport.
- bool IsInline = false, IsStaticDataMember = false;
+ bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false;
if (const auto *VD = dyn_cast<VarDecl>(NewDecl))
// Ignore static data because out-of-line definitions are diagnosed
// separately.
IsStaticDataMember = VD->isStaticDataMember();
- else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl))
+ else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl)) {
IsInline = FD->isInlined();
+ IsQualifiedFriend = FD->getQualifier() &&
+ FD->getFriendObjectKind() == Decl::FOK_Declared;
+ }
if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember &&
- !NewDecl->isLocalExternDecl()) {
+ !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) {
S.Diag(NewDecl->getLocation(),
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
<< NewDecl << OldImportAttr;
// GNU-DAG: declare void @_Z7friend2v()
// MSC-DAG: define void @"\01?friend3@@YAXXZ"()
// GNU-DAG: define void @_Z7friend3v()
+// MSC-DAG: declare void @"\01?friend4@@YAXXZ"()
+// GNU-DAG: declare void @_Z7friend4v()
+// MSC-DAG: declare dllimport void @"\01?friend5@@YAXXZ"()
+// GNU-DAG: declare dllimport void @_Z7friend5v()
+
struct FuncFriend {
friend __declspec(dllimport) void friend1();
friend __declspec(dllimport) void friend2();
__declspec(dllimport) void friend1();
void friend2(); // dllimport ignored
void friend3() {} // dllimport ignored
+
+__declspec(dllimport) void friend4();
+__declspec(dllimport) void friend5();
+struct FuncFriendRedecl {
+ friend void friend4(); // dllimport ignored
+ friend void ::friend5();
+};
USE(friend1)
USE(friend2)
USE(friend3)
+USE(friend4)
+USE(friend5)
// Implicit declarations can be redeclared with dllimport.
// MSC-DAG: declare dllimport noalias i8* @"\01??2@{{YAPAXI|YAPEAX_K}}@Z"(
__declspec(dllimport) void friend4(); // expected-error{{redeclaration of 'friend4' cannot add 'dllimport' attribute}}
__declspec(dllimport) inline void friend5() {} // expected-error{{redeclaration of 'friend5' cannot add 'dllimport' attribute}}
+void __declspec(dllimport) friend6(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+void __declspec(dllimport) friend7();
+struct FuncFriend2 {
+ friend void friend6(); // expected-warning{{'friend6' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+ friend void ::friend7();
+};
+
// Implicit declarations can be redeclared with dllimport.
__declspec(dllimport) void* operator new(__SIZE_TYPE__ n);