]> granicus.if.org Git - clang/commitdiff
Sema: Check dll attributes on redeclarations
authorNico Rieck <nico.rieck@gmail.com>
Mon, 31 Mar 2014 14:56:15 +0000 (14:56 +0000)
committerNico Rieck <nico.rieck@gmail.com>
Mon, 31 Mar 2014 14:56:15 +0000 (14:56 +0000)
A redeclaration may not add dllimport or dllexport attributes. dllexport is
sticky and can be omitted on redeclarations while dllimport cannot.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205197 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
test/Sema/dllexport.c
test/Sema/dllimport.c
test/SemaCXX/MicrosoftExtensions.cpp
test/SemaCXX/dllexport.cpp
test/SemaCXX/dllimport.cpp

index 1a6784bef97dcc351e4c01c320e1f93e93f7f01d..bd461f4597a17e6690639f77472a737961cebaa7 100644 (file)
@@ -2077,6 +2077,8 @@ def err_attribute_selectany_non_extern_data : Error<
 def warn_attribute_invalid_on_definition : Warning<
   "'%0' attribute cannot be specified on a definition">,
   InGroup<IgnoredAttributes>;
+def err_attribute_dll_redeclaration : Error<
+  "redeclaration of %q0 cannot add %q1 attribute">;
 def err_attribute_dllimport_data_definition : Error<
   "definition of dllimport data">;
 def err_attribute_weakref_not_static : Error<
index 82579d89cd2c8c5fceb32088832e6d831965e070..26f8b2587fddb594f6d0651132db2c0e47bf54cd 100644 (file)
@@ -4845,6 +4845,56 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
   }
 }
 
+static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
+                                           NamedDecl *NewDecl,
+                                           bool IsSpecialization) {
+  if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl))
+    OldDecl = OldTD->getTemplatedDecl();
+  if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl))
+    NewDecl = NewTD->getTemplatedDecl();
+
+  if (!OldDecl || !NewDecl)
+      return;
+
+  const DLLImportAttr *OldImportAttr = OldDecl->getAttr<DLLImportAttr>();
+  const DLLExportAttr *OldExportAttr = OldDecl->getAttr<DLLExportAttr>();
+  const DLLImportAttr *NewImportAttr = NewDecl->getAttr<DLLImportAttr>();
+  const DLLExportAttr *NewExportAttr = NewDecl->getAttr<DLLExportAttr>();
+
+  // dllimport and dllexport are inheritable attributes so we have to exclude
+  // inherited attribute instances.
+  bool HasNewAttr = (NewImportAttr && !NewImportAttr->isInherited()) ||
+                    (NewExportAttr && !NewExportAttr->isInherited());
+
+  // A redeclaration is not allowed to add a dllimport or dllexport attribute,
+  // the only exception being explicit specializations.
+  // Implicitly generated declarations are also excluded for now because there
+  // is no other way to switch these to use dllimport or dllexport.
+  bool AddsAttr = !(OldImportAttr || OldExportAttr) && HasNewAttr;
+  if (AddsAttr && !IsSpecialization && !OldDecl->isImplicit()) {
+    S.Diag(NewDecl->getLocation(), diag::err_attribute_dll_redeclaration)
+      << NewDecl
+      << (NewImportAttr ? (const Attr *)NewImportAttr : NewExportAttr);
+    S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
+    NewDecl->setInvalidDecl();
+    return;
+  }
+
+  // A redeclaration is not allowed to drop a dllimport attribute, the only
+  // exception being inline function definitions.
+  // FIXME: Handle inline functions.
+  // NB: MSVC converts such a declaration to dllexport.
+  if (OldImportAttr && !HasNewAttr) {
+    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<DLLImportAttr>();
+    NewDecl->dropAttr<DLLImportAttr>();
+  }
+}
+
 /// Given that we are within the definition of the given function,
 /// will that definition behave like C99's 'inline', where the
 /// definition is discarded except for optimization purposes?
@@ -5497,6 +5547,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
     }
   }
 
+  if (D.isRedeclaration() && !Previous.empty()) {
+    checkDLLAttributeRedeclaration(
+        *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewVD,
+        IsExplicitSpecialization);
+  }
+
   if (NewTemplate) {
     if (NewVD->isInvalidDecl())
       NewTemplate->setInvalidDecl();
@@ -7318,6 +7374,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   // Set this FunctionDecl's range up to the right paren.
   NewFD->setRangeEnd(D.getSourceRange().getEnd());
 
+  if (D.isRedeclaration() && !Previous.empty()) {
+    checkDLLAttributeRedeclaration(
+        *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewFD,
+        isExplicitSpecialization || isFunctionTemplateSpecialization);
+  }
+
   if (getLangOpts().CPlusPlus) {
     if (FunctionTemplate) {
       if (NewFD->isInvalidDecl())
@@ -9679,17 +9741,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
       FD->setInvalidDecl();
       return D;
     }
-
-    // Visual C++ appears to not think this is an issue, so only issue
-    // a warning when Microsoft extensions are disabled.
-    if (!LangOpts.MicrosoftExt) {
-      // If a symbol previously declared dllimport is later defined, the
-      // attribute is ignored in subsequent references, and a warning is
-      // emitted.
-      Diag(FD->getLocation(),
-           diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
-        << FD << DA;
-    }
   }
   // We want to attach documentation to original Decl (which might be
   // a function template).
index eb39fbe9bf2dfef515a68f8b402e0f09c6c67390..675bd492f8564ddf93270a703b5897297bedeb9f 100644 (file)
@@ -31,6 +31,16 @@ int __declspec(dllexport) GlobalInit2 = 1;
 __declspec(dllexport) extern int GlobalDeclInit;
 int GlobalDeclInit = 1;
 
+// Redeclarations
+__declspec(dllexport) extern int GlobalRedecl1;
+__declspec(dllexport)        int GlobalRedecl1;
+
+__declspec(dllexport) extern int GlobalRedecl2;
+                             int GlobalRedecl2;
+
+                      extern int GlobalRedecl3; // expected-note{{previous declaration is here}}
+__declspec(dllexport) extern int GlobalRedecl3; // expected-error{{redeclaration of 'GlobalRedecl3' cannot add 'dllexport' attribute}}
+
 // Export in local scope.
 void functionScope() {
   __declspec(dllexport) extern int ExternLocalVarDecl;
@@ -69,6 +79,9 @@ __declspec(dllexport) void redecl2();
 __declspec(dllexport) void redecl3();
                       void redecl3() {}
 
+                      void redecl4(); // expected-note{{previous declaration is here}}
+__declspec(dllexport) void redecl4(); // expected-error{{redeclaration of 'redecl4' cannot add 'dllexport' attribute}}
+
 
 
 //===----------------------------------------------------------------------===//
index 0bd4afc8b86e866e9593b518543ad985984a1736..46031173cd2dc13b8eca6c65a486a278d8d643f0 100644 (file)
@@ -31,17 +31,17 @@ __declspec(dllimport) int GlobalInit1 = 1; // expected-error{{definition of dlli
 int __declspec(dllimport) GlobalInit2 = 1; // expected-error{{definition of dllimport data}}
 
 // Declare, then reject definition.
-__declspec(dllimport) extern int ExternGlobalDeclInit;
-int ExternGlobalDeclInit = 1; // expected-error{{definition of dllimport data}}
+__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}}
 
-__declspec(dllimport) int GlobalDeclInit;
-int GlobalDeclInit = 1; // expected-error{{definition of dllimport data}}
+__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}}
 
-int *__attribute__((dllimport)) GlobalDeclChunkAttrInit;
-int *GlobalDeclChunkAttrInit = 0; // expected-error{{definition of dllimport data}}
+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}}
 
-int GlobalDeclAttrInit __attribute__((dllimport));
-int GlobalDeclAttrInit = 1; // expected-error{{definition of dllimport data}}
+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}}
 
 // Redeclarations
 __declspec(dllimport) extern int GlobalRedecl1;
@@ -56,6 +56,14 @@ int *__attribute__((dllimport)) GlobalRedecl2b;
 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}}
+
+                      extern int GlobalRedecl4; // expected-note{{previous declaration is here}}
+__declspec(dllimport) extern int GlobalRedecl4; // expected-error{{redeclaration of 'GlobalRedecl4' cannot add 'dllimport' attribute}}
+
 // Import in local scope.
 __declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}}
 __declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}}
@@ -95,5 +103,13 @@ inline void __attribute__((dllimport)) inlineFunc2() {} // expected-warning{{'dl
 __declspec(dllimport) void redecl1();
 __declspec(dllimport) void redecl1();
 
-__declspec(dllimport) void redecl3();
+// 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}}
+
+                      void redecl4(); // expected-note{{previous declaration is here}}
+__declspec(dllimport) void redecl4(); // expected-error{{redeclaration of 'redecl4' cannot add 'dllimport' attribute}}
index 9f7bcc625f40b1fe90baad5a13afb14e690a4643..0f6ebbb069942db55dd9dbe1ed3d0d4238e7ed55 100644 (file)
@@ -119,10 +119,11 @@ enum : long long {  // expected-warning{{enumeration types with a fixed underlyi
 
 class AAA {
 __declspec(dllimport) void f(void) { }
-void f2(void);
+void f2(void); // expected-note{{previous declaration is here}}
 };
 
-__declspec(dllimport) void AAA::f2(void) { // expected-error {{'dllimport' attribute can be applied only to symbol}}
+__declspec(dllimport) void AAA::f2(void) { // expected-error{{'dllimport' attribute can be applied only to symbol}}
+                                           // expected-error@-1{{redeclaration of 'AAA::f2' cannot add 'dllimport' attribute}}
 
 }
 
index 647638349569f739b0c40973d0e5ebf9732f0b6b..acbd4ce78f4ce9e41942a8baef504879b35bb377 100644 (file)
@@ -43,6 +43,16 @@ int __declspec(dllexport) GlobalInit2 = 1;
 __declspec(dllexport) extern int GlobalDeclInit;
 int GlobalDeclInit = 1;
 
+// Redeclarations
+__declspec(dllexport) extern int GlobalRedecl1;
+__declspec(dllexport)        int GlobalRedecl1;
+
+__declspec(dllexport) extern int GlobalRedecl2;
+                             int GlobalRedecl2;
+
+                      extern int GlobalRedecl3; // expected-note{{previous declaration is here}}
+__declspec(dllexport) extern int GlobalRedecl3; // expected-error{{redeclaration of 'GlobalRedecl3' cannot add 'dllexport' attribute}}
+
 // Export in local scope.
 void functionScope() {
   __declspec(dllexport) extern int ExternLocalVarDecl;
@@ -84,6 +94,22 @@ __declspec(dllexport) void redecl1() {}
 __declspec(dllexport) void redecl2();
                       void redecl2() {}
 
+                      void redecl3(); // expected-note{{previous declaration is here}}
+__declspec(dllexport) void redecl3(); // expected-error{{redeclaration of 'redecl3' cannot add 'dllexport' attribute}}
+
+// Friend functions
+struct FuncFriend {
+  friend __declspec(dllexport) void friend1();
+  friend __declspec(dllexport) void friend2();
+  friend                       void friend3(); // expected-note{{previous declaration is here}}
+};
+__declspec(dllexport) void friend1() {}
+                      void friend2() {}
+__declspec(dllexport) void friend3() {} // expected-error{{redeclaration of 'friend3' cannot add 'dllexport' attribute}}
+
+// Implicit declarations can be redeclared with dllexport.
+__declspec(dllexport) void* operator new(__SIZE_TYPE__ n);
+
 
 
 //===----------------------------------------------------------------------===//
@@ -104,8 +130,18 @@ template<typename T> __declspec(dllexport) void funcTmplRedecl1() {}
 template<typename T> __declspec(dllexport) void funcTmplRedecl2();
 template<typename T>                       void funcTmplRedecl2() {}
 
-template<typename T> __declspec(dllexport) void funcTmplRedecl3();
-template<typename T>                       void funcTmplRedecl3() {}
+template<typename T>                       void funcTmplRedecl3(); // expected-note{{previous declaration is here}}
+template<typename T> __declspec(dllexport) void funcTmplRedecl3(); // expected-error{{redeclaration of 'funcTmplRedecl3' cannot add 'dllexport' attribute}}
+
+// Function template friends
+struct FuncTmplFriend {
+  template<typename T> friend __declspec(dllexport) void funcTmplFriend1();
+  template<typename T> friend __declspec(dllexport) void funcTmplFriend2();
+  template<typename T> friend                       void funcTmplFriend3(); // expected-note{{previous declaration is here}}
+};
+template<typename T> __declspec(dllexport) void funcTmplFriend1() {}
+template<typename T>                       void funcTmplFriend2() {}
+template<typename T> __declspec(dllexport) void funcTmplFriend3() {} // expected-error{{redeclaration of 'funcTmplFriend3' cannot add 'dllexport' attribute}}
 
 
 template<typename T> void funcTmpl() {}
index c36718b542f473e9a17674ebfcc20c020dc6d51e..f63943924c694ce891b813b4a3425f51b05952a1 100644 (file)
@@ -43,17 +43,17 @@ __declspec(dllimport) int GlobalInit1 = 1; // expected-error{{definition of dlli
 int __declspec(dllimport) GlobalInit2 = 1; // expected-error{{definition of dllimport data}}
 
 // Declare, then reject definition.
-__declspec(dllimport) extern int ExternGlobalDeclInit;
-int ExternGlobalDeclInit = 1; // expected-error{{definition of dllimport data}}
+__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}}
 
-__declspec(dllimport) int GlobalDeclInit;
-int GlobalDeclInit = 1; // expected-error{{definition of dllimport data}}
+__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}}
 
-int *__attribute__((dllimport)) GlobalDeclChunkAttrInit;
-int *GlobalDeclChunkAttrInit = 0; // expected-error{{definition of dllimport data}}
+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}}
 
-int GlobalDeclAttrInit __attribute__((dllimport));
-int GlobalDeclAttrInit = 1; // expected-error{{definition of dllimport data}}
+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}}
 
 // Redeclarations
 __declspec(dllimport) extern int GlobalRedecl1;
@@ -68,6 +68,14 @@ int *__attribute__((dllimport)) GlobalRedecl2b;
 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}}
+
+                      extern int GlobalRedecl4; // expected-note{{previous declaration is here}}
+__declspec(dllimport) extern int GlobalRedecl4; // expected-error{{redeclaration of 'GlobalRedecl4' cannot add 'dllimport' attribute}}
+
 // Import in local scope.
 __declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}}
 __declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}}
@@ -110,9 +118,32 @@ inline void __attribute__((dllimport)) inlineFunc2() {} // expected-warning{{'dl
 __declspec(dllimport) void redecl1();
 __declspec(dllimport) void redecl1();
 
-__declspec(dllimport) void redecl3();
+// 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}}
 
+                      void redecl4(); // expected-note{{previous declaration is here}}
+__declspec(dllimport) void redecl4(); // expected-error{{redeclaration of 'redecl4' cannot add 'dllimport' attribute}}
+
+// Friend functions
+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}}
+  friend                       void friend4(); // expected-note{{previous declaration is here}}
+};
+__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}}
+__declspec(dllimport) void friend4(); // expected-error{{redeclaration of 'friend4' cannot add 'dllimport' attribute}}
+
+// Implicit declarations can be redeclared with dllimport.
+__declspec(dllimport) void* operator new(__SIZE_TYPE__ n);
+
 
 
 //===----------------------------------------------------------------------===//
@@ -127,12 +158,27 @@ template<typename T> void __declspec(dllimport) funcTmplDecl2();
 template<typename T> __declspec(dllimport) void funcTmplRedecl1();
 template<typename T> __declspec(dllimport) void funcTmplRedecl1();
 
-template<typename T> __declspec(dllimport) void funcTmplRedecl2();
-template<typename T>                       void funcTmplRedecl2();
+template<typename T> __declspec(dllimport) void funcTmplRedecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+template<typename T>                       void funcTmplRedecl2(); // expected-warning{{'funcTmplRedecl2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
 
-template<typename T> __declspec(dllimport) void funcTmplRedecl3();
+template<typename T> __declspec(dllimport) void funcTmplRedecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
 template<typename T>                       void funcTmplRedecl3() {} // expected-warning{{'funcTmplRedecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
 
+template<typename T>                       void funcTmplRedecl4(); // expected-note{{previous declaration is here}}
+template<typename T> __declspec(dllimport) void funcTmplRedecl4(); // expected-error{{redeclaration of 'funcTmplRedecl4' cannot add 'dllimport' attribute}}
+
+// Function template friends
+struct FuncTmplFriend {
+  template<typename T> friend __declspec(dllimport) void funcTmplFriend1();
+  template<typename T> friend __declspec(dllimport) void funcTmplFriend2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+  template<typename T> friend __declspec(dllimport) void funcTmplFriend3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+  template<typename T> friend                       void funcTmplFriend4(); // expected-note{{previous declaration is here}}
+};
+template<typename T> __declspec(dllimport) void funcTmplFriend1();
+template<typename T>                       void funcTmplFriend2(); // expected-warning{{'funcTmplFriend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+template<typename T>                       void funcTmplFriend3() {} // expected-warning{{'funcTmplFriend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+template<typename T> __declspec(dllimport) void funcTmplFriend4(); // expected-error{{redeclaration of 'funcTmplFriend4' cannot add 'dllimport' attribute}}
+
 
 template<typename T> void funcTmpl() {}
 template<typename T> __declspec(dllimport) void importedFuncTmpl();