Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2351,6 +2351,9 @@ def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< "%q0 redeclared without %1 attribute: previous %1 ignored">, InGroup>; +def warn_redeclaration_without_import_attribute : Warning< + "%q0 redeclared without 'dllimport' attribute: 'dllexport' attribute added">, + InGroup>; def warn_dllimport_dropped_from_inline_function : Warning< "%q0 redeclared inline; %1 attribute ignored">, InGroup; @@ -2884,6 +2887,7 @@ InGroup>; def err_mismatched_visibility: Error<"visibility does not match previous declaration">; def note_previous_attribute : Note<"previous attribute is here">; +def note_previous_attribute_replaced : Note<"previous attribute is here: replaced with 'dllexport'">; def note_conflicting_attribute : Note<"conflicting attribute is here">; def note_attribute : Note<"attribute is here">; def err_mismatched_ms_inheritance : Error< Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -5504,9 +5504,13 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, NamedDecl *NewDecl, - bool IsSpecialization) { - if (TemplateDecl *OldTD = dyn_cast(OldDecl)) + bool IsSpecialization, + bool IsDefinition = false) { + if (TemplateDecl *OldTD = dyn_cast(OldDecl)) { OldDecl = OldTD->getTemplatedDecl(); + if (!IsSpecialization) + IsDefinition = false; + } if (TemplateDecl *NewTD = dyn_cast(NewDecl)) NewDecl = NewTD->getTemplatedDecl(); @@ -5563,12 +5567,16 @@ // A redeclaration is not allowed to drop a dllimport attribute, the only // exceptions being inline function definitions, local extern declarations, // and qualified friend declarations. - // NB: MSVC converts such a declaration to dllexport. + // NB: MSVC converts such a declaration to dllexport that's why we do it also. bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false; - if (const auto *VD = dyn_cast(NewDecl)) + bool isMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft(); + if (const auto *VD = dyn_cast(NewDecl)) { // Ignore static data because out-of-line definitions are diagnosed // separately. IsStaticDataMember = VD->isStaticDataMember(); + IsDefinition = + !VD->isThisDeclarationADefinition(S.Context) == VarDecl::DeclarationOnly; + } else if (const auto *FD = dyn_cast(NewDecl)) { IsInline = FD->isInlined(); IsQualifiedFriend = FD->getQualifier() && @@ -5577,15 +5585,31 @@ if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember && !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) { - S.Diag(NewDecl->getLocation(), - diag::warn_redeclaration_without_attribute_prev_attribute_ignored) - << NewDecl << OldImportAttr; - S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); - S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); - OldDecl->dropAttr(); - NewDecl->dropAttr(); - } else if (IsInline && OldImportAttr && - !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + if (isMicrosoft && IsDefinition) { + S.Diag(NewDecl->getLocation(), + diag::warn_redeclaration_without_import_attribute) << NewDecl; + S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); + S.Diag(OldImportAttr->getLocation(), + diag::note_previous_attribute_replaced); + // Replace DLLImportAttr with DLLExportAttr + OldDecl->dropAttr(); + NewDecl->dropAttr(); + OldDecl->addAttr(::new (S.Context) DLLExportAttr( + OldImportAttr->getRange(), S.Context, + OldImportAttr->getSpellingListIndex())); + NewDecl->addAttr(::new (S.Context) DLLExportAttr( + NewImportAttr->getRange(), S.Context, + NewImportAttr->getSpellingListIndex())); + } else { + S.Diag(NewDecl->getLocation(), + diag::warn_redeclaration_without_attribute_prev_attribute_ignored) + << NewDecl << OldImportAttr; + S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); + S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); + OldDecl->dropAttr(); + NewDecl->dropAttr(); + } + } else if (IsInline && OldImportAttr && !isMicrosoft) { // In MinGW, seeing a function declared inline drops the dllimport attribute. OldDecl->dropAttr(); NewDecl->dropAttr(); @@ -6369,7 +6393,8 @@ if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast(Previous.getRepresentativeDecl()), NewVD, - IsExplicitSpecialization); + IsExplicitSpecialization, + D.isFunctionDefinition()); } if (NewTemplate) { @@ -8368,7 +8393,8 @@ if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast(Previous.getRepresentativeDecl()), NewFD, - isExplicitSpecialization || isFunctionTemplateSpecialization); + isExplicitSpecialization || isFunctionTemplateSpecialization, + D.isFunctionDefinition()); } if (getLangOpts().CUDA) { Index: test/CodeGen/dllimport.c =================================================================== --- test/CodeGen/dllimport.c +++ test/CodeGen/dllimport.c @@ -45,7 +45,8 @@ USEVAR(GlobalRedecl3) // Make sure this works even if the decl has been used before it's defined (PR20792). -// CHECK: @GlobalRedecl4 = common global i32 +// MS: @GlobalRedecl4 = common dllexport global i32 +// GNU: @GlobalRedecl4 = common global i32 __declspec(dllimport) extern int GlobalRedecl4; USEVAR(GlobalRedecl4) int GlobalRedecl4; // dllimport ignored @@ -111,13 +112,15 @@ void redecl2(void); USE(redecl2) -// CHECK-DAG: define void @redecl3() +// MS: define dllexport void @redecl3() +// GNU: define void @redecl3() __declspec(dllimport) void redecl3(void); void redecl3(void) {} // dllimport ignored USE(redecl3) // Make sure this works even if the decl is used before it's defined (PR20792). -// CHECK-DAG: define void @redecl4() +// MS: define dllexport void @redecl4() +// GNU: define void @redecl4() __declspec(dllimport) void redecl4(void); USE(redecl4) void redecl4(void) {} // dllimport ignored Index: test/CodeGenCXX/dllimport-members.cpp =================================================================== --- test/CodeGenCXX/dllimport-members.cpp +++ test/CodeGenCXX/dllimport-members.cpp @@ -63,8 +63,8 @@ struct ImportMembers { struct Nested; - // M32-DAG: define x86_thiscallcc void @"\01?normalDef@ImportMembers@@QAEXXZ"(%struct.ImportMembers* %this) - // M64-DAG: define void @"\01?normalDef@ImportMembers@@QEAAXXZ"(%struct.ImportMembers* %this) + // M32-DAG: define dllexport x86_thiscallcc void @"\01?normalDef@ImportMembers@@QAEXXZ"(%struct.ImportMembers* %this) + // M64-DAG: define dllexport void @"\01?normalDef@ImportMembers@@QEAAXXZ"(%struct.ImportMembers* %this) // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalDecl@ImportMembers@@QAEXXZ"(%struct.ImportMembers*) // M64-DAG: declare dllimport void @"\01?normalDecl@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*) // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInclass@ImportMembers@@QAEXXZ"(%struct.ImportMembers*) @@ -95,8 +95,8 @@ __declspec(dllimport) void normalInlineDef(); __declspec(dllimport) inline void normalInlineDecl(); - // M32-DAG: define x86_thiscallcc void @"\01?virtualDef@ImportMembers@@UAEXXZ"(%struct.ImportMembers* %this) - // M64-DAG: define void @"\01?virtualDef@ImportMembers@@UEAAXXZ"(%struct.ImportMembers* %this) + // M32-DAG: define dllexport x86_thiscallcc void @"\01?virtualDef@ImportMembers@@UAEXXZ"(%struct.ImportMembers* %this) + // M64-DAG: define dllexport void @"\01?virtualDef@ImportMembers@@UEAAXXZ"(%struct.ImportMembers* %this) // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualDecl@ImportMembers@@UAEXXZ"(%struct.ImportMembers*) // M64-DAG: declare dllimport void @"\01?virtualDecl@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*) // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInclass@ImportMembers@@UAEXXZ"(%struct.ImportMembers*) @@ -127,7 +127,7 @@ __declspec(dllimport) virtual void virtualInlineDef(); __declspec(dllimport) virtual inline void virtualInlineDecl(); - // MSC-DAG: define void @"\01?staticDef@ImportMembers@@SAXXZ"() + // MSC-DAG: define dllexport void @"\01?staticDef@ImportMembers@@SAXXZ"() // MSC-DAG: declare dllimport void @"\01?staticDecl@ImportMembers@@SAXXZ"() // MSC-DAG: declare dllimport void @"\01?staticInclass@ImportMembers@@SAXXZ"() // MSC-DAG: declare dllimport void @"\01?staticInlineDef@ImportMembers@@SAXXZ"() @@ -235,8 +235,8 @@ // Import individual members of a nested class. struct ImportMembers::Nested { - // M32-DAG: define x86_thiscallcc void @"\01?normalDef@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"* %this) - // M64-DAG: define void @"\01?normalDef@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"* %this) + // M32-DAG: define dllexport x86_thiscallcc void @"\01?normalDef@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"* %this) + // M64-DAG: define dllexport void @"\01?normalDef@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"* %this) // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalDecl@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*) // M64-DAG: declare dllimport void @"\01?normalDecl@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*) // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInclass@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*) @@ -267,8 +267,8 @@ __declspec(dllimport) void normalInlineDef(); __declspec(dllimport) inline void normalInlineDecl(); - // M32-DAG: define x86_thiscallcc void @"\01?virtualDef@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"* %this) - // M64-DAG: define void @"\01?virtualDef@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"* %this) + // M32-DAG: define dllexport x86_thiscallcc void @"\01?virtualDef@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"* %this) + // M64-DAG: define dllexport void @"\01?virtualDef@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"* %this) // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualDecl@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*) // M64-DAG: declare dllimport void @"\01?virtualDecl@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*) // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInclass@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*) @@ -300,7 +300,7 @@ __declspec(dllimport) virtual void virtualInlineDef(); __declspec(dllimport) virtual inline void virtualInlineDecl(); - // MSC-DAG: define void @"\01?staticDef@Nested@ImportMembers@@SAXXZ"() + // MSC-DAG: define dllexport void @"\01?staticDef@Nested@ImportMembers@@SAXXZ"() // MSC-DAG: declare dllimport void @"\01?staticDecl@Nested@ImportMembers@@SAXXZ"() // MSC-DAG: declare dllimport void @"\01?staticInclass@Nested@ImportMembers@@SAXXZ"() // MSC-DAG: declare dllimport void @"\01?staticInlineDef@Nested@ImportMembers@@SAXXZ"() @@ -595,16 +595,16 @@ // G64-DAG: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @_ZN19ImportDefaultedDefsaSERKS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) inline ImportDefaultedDefs& ImportDefaultedDefs::operator=(const ImportDefaultedDefs&) = default; -// M32-DAG: define x86_thiscallcc %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QAE@$$QAU0@@Z"(%struct.ImportDefaultedDefs* returned %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) -// M64-DAG: define %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QEAA@$$QEAU0@@Z"(%struct.ImportDefaultedDefs* returned %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) +// M32-DAG: define dllexport x86_thiscallcc %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QAE@$$QAU0@@Z"(%struct.ImportDefaultedDefs* returned %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) +// M64-DAG: define dllexport %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QEAA@$$QEAU0@@Z"(%struct.ImportDefaultedDefs* returned %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) // G32-DAG: define x86_thiscallcc void @_ZN19ImportDefaultedDefsC1EOS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) // G64-DAG: define void @_ZN19ImportDefaultedDefsC1EOS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) // G32-DAG: define x86_thiscallcc void @_ZN19ImportDefaultedDefsC2EOS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) // G64-DAG: define void @_ZN19ImportDefaultedDefsC2EOS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) ImportDefaultedDefs::ImportDefaultedDefs(ImportDefaultedDefs&&) = default; // dllimport ignored -// M32-DAG: define x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @"\01??4ImportDefaultedDefs@@QAEAAU0@$$QAU0@@Z"(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) -// M64-DAG: define dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @"\01??4ImportDefaultedDefs@@QEAAAEAU0@$$QEAU0@@Z"(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) +// M32-DAG: define dllexport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @"\01??4ImportDefaultedDefs@@QAEAAU0@$$QAU0@@Z"(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) +// M64-DAG: define dllexport dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @"\01??4ImportDefaultedDefs@@QEAAAEAU0@$$QEAU0@@Z"(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) // G32-DAG: define x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @_ZN19ImportDefaultedDefsaSEOS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) // G64-DAG: define dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @_ZN19ImportDefaultedDefsaSEOS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}})) ImportDefaultedDefs& ImportDefaultedDefs::operator=(ImportDefaultedDefs&&) = default; // dllimport ignored Index: test/CodeGenCXX/dllimport.cpp =================================================================== --- test/CodeGenCXX/dllimport.cpp +++ test/CodeGenCXX/dllimport.cpp @@ -264,7 +264,7 @@ void redecl2(); USE(redecl2) -// MSC-DAG: define void @"\01?redecl3@@YAXXZ"() +// MSC-DAG: define dllexport void @"\01?redecl3@@YAXXZ"() // GNU-DAG: define void @_Z7redecl3v() __declspec(dllimport) void redecl3(); void redecl3() {} // dllimport ignored @@ -276,7 +276,7 @@ // GNU-DAG: declare dllimport void @_Z7friend1v() // MSC-DAG: declare void @"\01?friend2@@YAXXZ"() // GNU-DAG: declare void @_Z7friend2v() -// MSC-DAG: define void @"\01?friend3@@YAXXZ"() +// MSC-DAG: define dllexport void @"\01?friend3@@YAXXZ"() // GNU-DAG: define void @_Z7friend3v() // MSC-DAG: declare void @"\01?friend4@@YAXXZ"() // GNU-DAG: declare void @_Z7friend4v() Index: test/Sema/dllimport.c =================================================================== --- test/Sema/dllimport.c +++ test/Sema/dllimport.c @@ -35,16 +35,36 @@ // Declare, then reject definition. __declspec(dllimport) extern int ExternGlobalDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -int ExternGlobalDeclInit = 1; // expected-warning{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +int ExternGlobalDeclInit = 1; __declspec(dllimport) int GlobalDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -int GlobalDeclInit = 1; // expected-warning{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'GlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +int GlobalDeclInit = 1; int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -int *GlobalDeclChunkAttrInit = 0; // expected-warning{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +int *GlobalDeclChunkAttrInit = 0; int GlobalDeclAttrInit __attribute__((dllimport)); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -int GlobalDeclAttrInit = 1; // expected-warning{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +int GlobalDeclAttrInit = 1; // Redeclarations __declspec(dllimport) extern int GlobalRedecl1; @@ -59,8 +79,7 @@ int GlobalRedecl2c __attribute__((dllimport)); int GlobalRedecl2c __attribute__((dllimport)); -// NB: MSVC issues a warning and makes GlobalRedecl3 dllexport. We follow GCC -// and drop the dllimport with a warning. +// We follow GCC and drop the dllimport with a warning. __declspec(dllimport) extern int GlobalRedecl3; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} extern int GlobalRedecl3; // expected-warning{{'GlobalRedecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -133,13 +152,17 @@ __declspec(dllimport) void redecl1(); __declspec(dllimport) void redecl1(); -// NB: MSVC issues a warning and makes redecl2/redecl3 dllexport. We follow GCC -// and drop the dllimport with a warning. __declspec(dllimport) void redecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} void redecl2(); // expected-warning{{'redecl2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} __declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} - void redecl3() {} // expected-warning{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +// NB: Both MSVC and Clang issue a warning and make redecl3 dllexport. +#ifdef MS +// expected-warning@+4{{'redecl3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif + void redecl3() {} void redecl4(); // expected-note{{previous declaration is here}} void useRedecl4() { redecl4(); } Index: test/SemaCXX/dllimport.cpp =================================================================== --- test/SemaCXX/dllimport.cpp +++ test/SemaCXX/dllimport.cpp @@ -45,16 +45,36 @@ // Declare, then reject definition. __declspec(dllimport) extern int ExternGlobalDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -int ExternGlobalDeclInit = 1; // expected-warning{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +int ExternGlobalDeclInit = 1; __declspec(dllimport) int GlobalDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -int GlobalDeclInit = 1; // expected-warning{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'GlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +int GlobalDeclInit = 1; int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -int *GlobalDeclChunkAttrInit = 0; // expected-warning{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +int *GlobalDeclChunkAttrInit = 0; int GlobalDeclAttrInit __attribute__((dllimport)); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -int GlobalDeclAttrInit = 1; // expected-warning{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +int GlobalDeclAttrInit = 1; // Redeclarations __declspec(dllimport) extern int GlobalRedecl1; @@ -69,8 +89,6 @@ int GlobalRedecl2c __attribute__((dllimport)); int GlobalRedecl2c __attribute__((dllimport)); -// NB: MSVC issues a warning and makes GlobalRedecl3 dllexport. We follow GCC -// and drop the dllimport with a warning. __declspec(dllimport) extern int GlobalRedecl3; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} extern int GlobalRedecl3; // expected-warning{{'GlobalRedecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -136,10 +154,20 @@ // Declare, then reject definition. template __declspec(dllimport) extern int ExternVarTmplDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -template int ExternVarTmplDeclInit = 1; // expected-warning{{'ExternVarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ExternVarTmplDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ExternVarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +template int ExternVarTmplDeclInit = 1; template __declspec(dllimport) int VarTmplDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -template int VarTmplDeclInit = 1; // expected-warning{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +template int VarTmplDeclInit = 1; // Redeclarations template __declspec(dllimport) extern int VarTmplRedecl1; @@ -238,13 +266,17 @@ __declspec(dllimport) void redecl1(); __declspec(dllimport) void redecl1(); -// NB: MSVC issues a warning and makes redecl2/redecl3 dllexport. We follow GCC -// and drop the dllimport with a warning. __declspec(dllimport) void redecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} void redecl2(); // expected-warning{{'redecl2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} __declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} - void redecl3() {} // expected-warning{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +// NB: Both MSVC and Clang issue a warning and make redecl3 dllexport. +#ifdef MS +// expected-warning@+4{{'redecl3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif + void redecl3() {} void redecl4(); // expected-note{{previous declaration is here}} __declspec(dllimport) void redecl4(); // expected-warning{{redeclaration of 'redecl4' should not add 'dllimport' attribute}} @@ -275,7 +307,12 @@ }; __declspec(dllimport) void friend1(); void friend2(); // expected-warning{{'friend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} - void friend3() {} // expected-warning{{'friend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'friend3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'friend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif + void friend3() {} __declspec(dllimport) void friend4(); // expected-warning{{redeclaration of 'friend4' should not add 'dllimport' attribute}} #ifdef MS __declspec(dllimport) inline void friend5() {} // expected-warning{{redeclaration of 'friend5' should not add 'dllimport' attribute}} @@ -495,20 +532,40 @@ __declspec(dllimport) constexpr static int ConstexprFieldDef = 1; // expected-note{{attribute is here}} }; - void ImportMembers::Nested::normalDef() {} // expected-warning{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} - void ImportMembers::normalDef() {} // expected-warning{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif + void ImportMembers::Nested::normalDef() {} +#ifdef MS +// expected-warning@+4{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif + void ImportMembers::normalDef() {} #ifdef GNU // expected-warning@+2{{'ImportMembers::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}} #endif inline void ImportMembers::normalInlineDef() {} void ImportMembers::normalInlineDecl() {} - void ImportMembers::virtualDef() {} // expected-warning{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif + void ImportMembers::virtualDef() {} #ifdef GNU // expected-warning@+2{{'ImportMembers::virtualInlineDef' redeclared inline; 'dllimport' attribute ignored}} #endif inline void ImportMembers::virtualInlineDef() {} void ImportMembers::virtualInlineDecl() {} - void ImportMembers::staticDef() {} // expected-warning{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif + void ImportMembers::staticDef() {} #ifdef GNU // expected-warning@+2{{'ImportMembers::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}} #endif @@ -636,8 +693,13 @@ // Not allowed on definitions. __declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs() = default; // expected-error{{dllimport cannot be applied to non-inline function definition}} +#ifdef MS +// expected-warning@+5{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+3{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif // dllimport cannot be dropped. -ImportDefaultedDefs::~ImportDefaultedDefs() = default; // expected-warning{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +ImportDefaultedDefs::~ImportDefaultedDefs() = default; // Import inline declaration and definition. #ifdef GNU @@ -648,7 +710,12 @@ inline ImportDefaultedDefs& ImportDefaultedDefs::operator=(const ImportDefaultedDefs&) = default; __declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs(ImportDefaultedDefs&&) = default; // expected-error{{dllimport cannot be applied to non-inline function definition}} -ImportDefaultedDefs& ImportDefaultedDefs::operator=(ImportDefaultedDefs&&) = default; // expected-warning{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +ImportDefaultedDefs& ImportDefaultedDefs::operator=(ImportDefaultedDefs&&) = default; // Redeclarations cannot add dllimport. @@ -1013,19 +1080,34 @@ // NB: MSVC is inconsistent here and disallows *InlineDef on class templates, // but allows it on classes. We allow both. -template void ImportClassTmplMembers::normalDef() {} // expected-warning{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +template void ImportClassTmplMembers::normalDef() {} #ifdef GNU // expected-warning@+2{{'ImportClassTmplMembers::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}} #endif template inline void ImportClassTmplMembers::normalInlineDef() {} template void ImportClassTmplMembers::normalInlineDecl() {} -template void ImportClassTmplMembers::virtualDef() {} // expected-warning{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +template void ImportClassTmplMembers::virtualDef() {} #ifdef GNU // expected-warning@+2{{'ImportClassTmplMembers::virtualInlineDef' redeclared inline; 'dllimport' attribute ignored}} #endif template inline void ImportClassTmplMembers::virtualInlineDef() {} template void ImportClassTmplMembers::virtualInlineDecl() {} -template void ImportClassTmplMembers::staticDef() {} // expected-warning{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef MS +// expected-warning@+4{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+2{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +template void ImportClassTmplMembers::staticDef() {} #ifdef GNU // expected-warning@+2{{'ImportClassTmplMembers::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}} #endif