Index: cfe/trunk/include/clang/Basic/DiagnosticGroups.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td @@ -772,6 +772,7 @@ def MicrosoftDefaultArgRedefinition : DiagGroup<"microsoft-default-arg-redefinition">; def MicrosoftTemplate : DiagGroup<"microsoft-template">; +def MicrosoftInconsistentDllImport : DiagGroup<"inconsistent-dllimport">; def MicrosoftRedeclareStatic : DiagGroup<"microsoft-redeclare-static">; def MicrosoftEnumForwardReference : DiagGroup<"microsoft-enum-forward-reference">; @@ -798,7 +799,8 @@ MicrosoftRedeclareStatic, MicrosoftEnumForwardReference, MicrosoftGoto, MicrosoftFlexibleArray, MicrosoftExtraQualification, MicrosoftCast, MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag, - MicrosoftCommentPaste, MicrosoftEndOfFile]>; + MicrosoftCommentPaste, MicrosoftEndOfFile, + MicrosoftInconsistentDllImport]>; def ClangClPch : DiagGroup<"clang-cl-pch">; Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -2359,7 +2359,10 @@ "requested alignment must be %0 bytes or smaller">; def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< "%q0 redeclared without %1 attribute: previous %1 ignored">, - InGroup>; + 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; Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -5559,9 +5559,13 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, NamedDecl *NewDecl, - bool IsSpecialization) { - if (TemplateDecl *OldTD = dyn_cast(OldDecl)) + bool IsSpecialization, + bool IsDefinition) { + if (TemplateDecl *OldTD = dyn_cast(OldDecl)) { OldDecl = OldTD->getTemplatedDecl(); + if (!IsSpecialization) + IsDefinition = false; + } if (TemplateDecl *NewTD = dyn_cast(NewDecl)) NewDecl = NewTD->getTemplatedDecl(); @@ -5617,14 +5621,17 @@ // 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. + // qualified friend declarations or special MSVC extension: in the last case, + // the declaration is treated as if it were marked dllexport. 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(); - else if (const auto *FD = dyn_cast(NewDecl)) { + IsDefinition = VD->isThisDeclarationADefinition(S.Context) != + VarDecl::DeclarationOnly; + } else if (const auto *FD = dyn_cast(NewDecl)) { IsInline = FD->isInlined(); IsQualifiedFriend = FD->getQualifier() && FD->getFriendObjectKind() == Decl::FOK_Declared; @@ -5632,15 +5639,25 @@ 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); + NewDecl->dropAttr(); + 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(); @@ -6424,7 +6441,7 @@ if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast(Previous.getRepresentativeDecl()), NewVD, - IsExplicitSpecialization); + IsExplicitSpecialization, D.isFunctionDefinition()); } if (NewTemplate) { @@ -8455,7 +8472,8 @@ if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast(Previous.getRepresentativeDecl()), NewFD, - isExplicitSpecialization || isFunctionTemplateSpecialization); + isExplicitSpecialization || isFunctionTemplateSpecialization, + D.isFunctionDefinition()); } if (getLangOpts().CUDA) { Index: cfe/trunk/test/CodeGen/dllimport.c =================================================================== --- cfe/trunk/test/CodeGen/dllimport.c +++ cfe/trunk/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: cfe/trunk/test/CodeGenCXX/dllimport-members.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/dllimport-members.cpp +++ cfe/trunk/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: cfe/trunk/test/CodeGenCXX/dllimport.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/dllimport.cpp +++ cfe/trunk/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: cfe/trunk/test/Sema/dllimport.c =================================================================== --- cfe/trunk/test/Sema/dllimport.c +++ cfe/trunk/test/Sema/dllimport.c @@ -34,17 +34,49 @@ int __declspec(dllimport) GlobalInit2 = 1; // expected-error{{definition of dllimport data}} // 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 GNU +// expected-note@+2{{previous attribute is here}} +#endif +__declspec(dllimport) extern int ExternGlobalDeclInit; // expected-note{{previous declaration is here}} +#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 GNU +// expected-note@+2{{previous attribute is here}} +#endif +__declspec(dllimport) int GlobalDeclInit; // expected-note{{previous declaration is here}} +#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 GNU +// expected-note@+2{{previous attribute is here}} +#endif +int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; // expected-note{{previous declaration is here}} +#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 GNU +// expected-note@+2{{previous attribute is here}} +#endif +int GlobalDeclAttrInit __attribute__((dllimport)); // expected-note{{previous declaration is here}} +#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 +91,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 +164,20 @@ __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}} +#ifdef GNU + // expected-note@+2{{previous attribute is here}} +#endif + __declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} + // 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: cfe/trunk/test/SemaCXX/dllimport.cpp =================================================================== --- cfe/trunk/test/SemaCXX/dllimport.cpp +++ cfe/trunk/test/SemaCXX/dllimport.cpp @@ -44,17 +44,49 @@ int __declspec(dllimport) GlobalInit2 = 1; // expected-error{{definition of dllimport data}} // 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 GNU +// expected-note@+2{{previous attribute is here}} +#endif +__declspec(dllimport) extern int ExternGlobalDeclInit; // expected-note{{previous declaration is here}} +#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 GNU +// expected-note@+2{{previous attribute is here}} +#endif +__declspec(dllimport) int GlobalDeclInit; // expected-note{{previous declaration is here}} +#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 GNU +// expected-note@+2{{previous attribute is here}} +#endif +int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; // expected-note{{previous declaration is here}} +#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 GNU +// expected-note@+2{{previous attribute is here}} +#endif +int GlobalDeclAttrInit __attribute__((dllimport)); // expected-note{{previous declaration is here}} +#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 +101,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}} @@ -135,11 +165,31 @@ template int __declspec(dllimport) VarTmplInit2 = 1; // expected-error{{definition of dllimport data}} // 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 GNU +// expected-note@+3{{previous attribute is here}} +#endif +template +__declspec(dllimport) extern int ExternVarTmplDeclInit; // expected-note{{previous declaration is here}} +#ifdef MS +// expected-warning@+5{{'ExternVarTmplDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+3{{'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 GNU +// expected-note@+3{{previous attribute is here}} +#endif +template +__declspec(dllimport) int VarTmplDeclInit; // expected-note{{previous declaration is here}} +#ifdef MS +// expected-warning@+5{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+3{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif +template +int VarTmplDeclInit = 1; // Redeclarations template __declspec(dllimport) extern int VarTmplRedecl1; @@ -238,13 +288,20 @@ __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}} +#ifdef GNU + // expected-note@+2{{previous attribute is here}} +#endif + __declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} + // 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}} @@ -266,7 +323,10 @@ struct FuncFriend { friend __declspec(dllimport) void friend1(); friend __declspec(dllimport) void friend2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} - friend __declspec(dllimport) void friend3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef GNU +// expected-note@+2{{previous attribute is here}} +#endif + friend __declspec(dllimport) void friend3(); // expected-note{{previous declaration is here}} friend void friend4(); // expected-note{{previous declaration is here}} #ifdef MS // expected-note@+2{{previous declaration is here}} @@ -275,7 +335,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}} @@ -447,33 +512,39 @@ struct ImportMembers { struct Nested { __declspec(dllimport) void normalDecl(); - __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef GNU +// expected-note@+2{{previous attribute is here}} +#endif + __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} }; #ifdef GNU +// expected-note@+5{{previous attribute is here}} // expected-warning@+5{{'dllimport' attribute ignored on inline function}} // expected-warning@+6{{'dllimport' attribute ignored on inline function}} #endif __declspec(dllimport) void normalDecl(); - __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} __declspec(dllimport) void normalInclass() {} __declspec(dllimport) void normalInlineDef(); __declspec(dllimport) inline void normalInlineDecl(); #ifdef GNU +// expected-note@+5{{previous attribute is here}} // expected-warning@+5{{'dllimport' attribute ignored on inline function}} // expected-warning@+6{{'dllimport' attribute ignored on inline function}} #endif __declspec(dllimport) virtual void virtualDecl(); - __declspec(dllimport) virtual void virtualDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) virtual void virtualDef(); // expected-note{{previous declaration is here}} __declspec(dllimport) virtual void virtualInclass() {} __declspec(dllimport) virtual void virtualInlineDef(); __declspec(dllimport) virtual inline void virtualInlineDecl(); #ifdef GNU +// expected-note@+5{{previous attribute is here}} // expected-warning@+5{{'dllimport' attribute ignored on inline function}} // expected-warning@+6{{'dllimport' attribute ignored on inline function}} #endif __declspec(dllimport) static void staticDecl(); - __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} __declspec(dllimport) static void staticInclass() {} __declspec(dllimport) static void staticInlineDef(); __declspec(dllimport) static inline void staticInlineDecl(); @@ -495,20 +566,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 @@ -620,7 +711,10 @@ // Import defaulted member function definitions. struct ImportDefaultedDefs { __declspec(dllimport) ImportDefaultedDefs(); - __declspec(dllimport) ~ImportDefaultedDefs(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef GNU +// expected-note@+2{{previous attribute is here}} +#endif + __declspec(dllimport) ~ImportDefaultedDefs(); // expected-note{{previous declaration is here}} #ifdef GNU // expected-warning@+3{{'dllimport' attribute ignored on inline function}} @@ -630,14 +724,22 @@ __declspec(dllimport) ImportDefaultedDefs& operator=(const ImportDefaultedDefs&); __declspec(dllimport) ImportDefaultedDefs(ImportDefaultedDefs&&); - __declspec(dllimport) ImportDefaultedDefs& operator=(ImportDefaultedDefs&&); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef GNU +// expected-note@+2{{previous attribute is here}} +#endif + __declspec(dllimport) ImportDefaultedDefs &operator=(ImportDefaultedDefs &&); // expected-note{{previous declaration is here}} }; // 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,8 +750,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. struct MemberRedecl { @@ -970,13 +1076,22 @@ template struct ImportClassTmplMembers { __declspec(dllimport) void normalDecl(); - __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef GNU +// expected-note@+2{{previous attribute is here}} +#endif + __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} __declspec(dllimport) void normalInlineDef(); __declspec(dllimport) virtual void virtualDecl(); - __declspec(dllimport) virtual void virtualDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef GNU +// expected-note@+2{{previous attribute is here}} +#endif + __declspec(dllimport) virtual void virtualDef(); // expected-note{{previous declaration is here}} __declspec(dllimport) virtual void virtualInlineDef(); __declspec(dllimport) static void staticDecl(); - __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef GNU +// expected-note@+2{{previous attribute is here}} +#endif + __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} __declspec(dllimport) static void staticInlineDef(); #ifdef GNU @@ -1013,19 +1128,37 @@ // 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@+5{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+3{{'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@+5{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+3{{'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@+5{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} +#else +// expected-warning@+3{{'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