Allow adding dll attributes on certain redecls with a warning if the decl hasn't been used yet (PR20746)

This shouldn't really be allowed, but it comes up in real code (see PR). As
long as the decl hasn't been used there's no technical difficulty in supporting
it, so downgrade the error to a warning.

Differential Revision: http://reviews.llvm.org/D5087

llvm-svn: 216619
This commit is contained in:
Hans Wennborg 2014-08-27 21:27:40 +00:00
parent cdb871d734
commit dd96db2c03
6 changed files with 66 additions and 21 deletions

View File

@ -2133,6 +2133,9 @@ def warn_attribute_invalid_on_definition : Warning<
InGroup<IgnoredAttributes>;
def err_attribute_dll_redeclaration : Error<
"redeclaration of %q0 cannot add %q1 attribute">;
def warn_attribute_dll_redeclaration : Warning<
"redeclaration of %q0 should not add %q1 attribute">,
InGroup<DiagGroup<"dll-attribute-on-redeclaration">>;
def err_attribute_dllimport_function_definition : Error<
"dllimport cannot be applied to non-inline function definition">;
def err_attribute_dll_deleted : Error<

View File

@ -5075,7 +5075,7 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
NewDecl = NewTD->getTemplatedDecl();
if (!OldDecl || !NewDecl)
return;
return;
const DLLImportAttr *OldImportAttr = OldDecl->getAttr<DLLImportAttr>();
const DLLExportAttr *OldExportAttr = OldDecl->getAttr<DLLExportAttr>();
@ -5092,13 +5092,30 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
// 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);
// If the declaration hasn't been used yet, allow with a warning for
// free functions and global variables.
bool JustWarn = false;
if (!OldDecl->isUsed() && OldDecl->getDeclContext()->isFileContext()) {
auto *VD = dyn_cast<VarDecl>(OldDecl);
if (VD && !VD->getDescribedVarTemplate())
JustWarn = true;
auto *FD = dyn_cast<FunctionDecl>(OldDecl);
if (FD && FD->getTemplatedKind() == FunctionDecl::TK_NonTemplate)
JustWarn = true;
}
unsigned DiagID = JustWarn ? diag::warn_attribute_dll_redeclaration
: diag::err_attribute_dll_redeclaration;
S.Diag(NewDecl->getLocation(), DiagID)
<< NewDecl
<< (NewImportAttr ? (const Attr *)NewImportAttr : NewExportAttr);
S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
NewDecl->setInvalidDecl();
return;
if (!JustWarn) {
NewDecl->setInvalidDecl();
return;
}
}
// A redeclaration is not allowed to drop a dllimport attribute, the only

View File

@ -39,8 +39,13 @@ __declspec(dllexport) extern int GlobalRedecl2;
int GlobalRedecl2;
extern int GlobalRedecl3; // expected-note{{previous declaration is here}}
int useGlobalRedecl3() { return GlobalRedecl3; }
__declspec(dllexport) extern int GlobalRedecl3; // expected-error{{redeclaration of 'GlobalRedecl3' cannot add 'dllexport' attribute}}
extern int GlobalRedecl4; // expected-note{{previous declaration is here}}
__declspec(dllexport) extern int GlobalRedecl4; // expected-warning{{redeclaration of 'GlobalRedecl4' should not add 'dllexport' attribute}}
// External linkage is required.
__declspec(dllexport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllexport'}}
@ -86,11 +91,18 @@ __declspec(dllexport) void redecl3();
void redecl3() {}
void redecl4(); // expected-note{{previous declaration is here}}
void useRedecl4() { redecl4(); }
__declspec(dllexport) void redecl4(); // expected-error{{redeclaration of 'redecl4' cannot add 'dllexport' attribute}}
void redecl5(); // expected-note{{previous declaration is here}}
void useRedecl5() { redecl5(); }
__declspec(dllexport) inline void redecl5() {} // expected-error{{redeclaration of 'redecl5' cannot add 'dllexport' attribute}}
// Allow with a warning if the decl hasn't been used yet.
void redecl6(); // expected-note{{previous declaration is here}}
__declspec(dllexport) void redecl6(); // expected-warning{{redeclaration of 'redecl6' should not add 'dllexport' attribute}}
// External linkage is required.
__declspec(dllexport) static int staticFunc(); // expected-error{{'staticFunc' must have external linkage when declared 'dllexport'}}

View File

@ -64,9 +64,16 @@ int GlobalRedecl2c __attribute__((dllimport));
__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}}
// Adding an attribute on redeclaration.
extern int GlobalRedecl4; // expected-note{{previous declaration is here}}
int useGlobalRedecl4() { return GlobalRedecl4; }
__declspec(dllimport) extern int GlobalRedecl4; // expected-error{{redeclaration of 'GlobalRedecl4' cannot add 'dllimport' attribute}}
// Allow with a warning if the decl hasn't been used yet.
extern int GlobalRedecl5; // expected-note{{previous declaration is here}}
__declspec(dllimport) extern int GlobalRedecl5; // expected-warning{{redeclaration of 'GlobalRedecl5' should not add 'dllimport' attribute}}
// External linkage is required.
__declspec(dllimport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllimport'}}
@ -128,14 +135,20 @@ __declspec(dllimport) void redecl3(); // expected-note{{previous declaration is
void redecl3() {} // expected-warning{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
void redecl4(); // expected-note{{previous declaration is here}}
void useRedecl4() { redecl4(); }
__declspec(dllimport) void redecl4(); // expected-error{{redeclaration of 'redecl4' cannot add 'dllimport' attribute}}
// Inline redeclarations are fine.
__declspec(dllimport) void redecl5();
inline void redecl5() {}
// Allow with a warning if the decl hasn't been used yet.
void redecl5(); // expected-note{{previous declaration is here}}
__declspec(dllimport) void redecl5(); // expected-warning{{redeclaration of 'redecl5' should not add 'dllimport' attribute}}
void redecl6(); // expected-note{{previous declaration is here}}
__declspec(dllimport) inline void redecl6() {} // expected-error{{redeclaration of 'redecl6' cannot add 'dllimport' attribute}}
// Inline redeclarations are fine.
__declspec(dllimport) void redecl6();
inline void redecl6() {}
void redecl7(); // expected-note{{previous declaration is here}}
__declspec(dllimport) inline void redecl7() {} // expected-warning{{redeclaration of 'redecl7' should not add 'dllimport' attribute}}
// External linkage is required.
__declspec(dllimport) static int staticFunc(); // expected-error{{'staticFunc' must have external linkage when declared 'dllimport'}}

View File

@ -53,7 +53,7 @@ __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}}
__declspec(dllexport) extern int GlobalRedecl3; // expected-warning{{redeclaration of 'GlobalRedecl3' should not add 'dllexport' attribute}}
// External linkage is required.
__declspec(dllexport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllexport'}}
@ -186,10 +186,10 @@ __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}}
__declspec(dllexport) void redecl3(); // expected-warning{{redeclaration of 'redecl3' should not add 'dllexport' attribute}}
void redecl4(); // expected-note{{previous declaration is here}}
__declspec(dllexport) inline void redecl4() {} // expected-error{{redeclaration of 'redecl4' cannot add 'dllexport' attribute}}
__declspec(dllexport) inline void redecl4() {} // expected-warning{{redeclaration of 'redecl4' should not add 'dllexport' attribute}}
// Friend functions
struct FuncFriend {
@ -200,8 +200,8 @@ struct FuncFriend {
};
__declspec(dllexport) void friend1() {}
void friend2() {}
__declspec(dllexport) void friend3() {} // expected-error{{redeclaration of 'friend3' cannot add 'dllexport' attribute}}
__declspec(dllexport) inline void friend4() {} // expected-error{{redeclaration of 'friend4' cannot add 'dllexport' attribute}}
__declspec(dllexport) void friend3() {} // expected-warning{{redeclaration of 'friend3' should not add 'dllexport' attribute}}
__declspec(dllexport) inline void friend4() {} // expected-warning{{redeclaration of 'friend4' should not add 'dllexport' attribute}}
// Implicit declarations can be redeclared with dllexport.
__declspec(dllexport) void* operator new(__SIZE_TYPE__ n);

View File

@ -75,7 +75,7 @@ __declspec(dllimport) extern int GlobalRedecl3; // expected-note{{previous decla
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}}
__declspec(dllimport) extern int GlobalRedecl4; // expected-warning{{redeclaration of 'GlobalRedecl4' should not add 'dllimport' attribute}}
// External linkage is required.
__declspec(dllimport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllimport'}}
@ -224,10 +224,10 @@ __declspec(dllimport) void redecl3(); // expected-note{{previous declaration is
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}}
__declspec(dllimport) void redecl4(); // expected-warning{{redeclaration of 'redecl4' should not add 'dllimport' attribute}}
void redecl5(); // expected-note{{previous declaration is here}}
__declspec(dllimport) inline void redecl5() {} // expected-error{{redeclaration of 'redecl5' cannot add 'dllimport' attribute}}
__declspec(dllimport) inline void redecl5() {} // expected-warning{{redeclaration of 'redecl5' should not add 'dllimport' attribute}}
// Friend functions
struct FuncFriend {
@ -240,8 +240,8 @@ struct FuncFriend {
__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}}
__declspec(dllimport) inline void friend5() {} // expected-error{{redeclaration of 'friend5' cannot add 'dllimport' attribute}}
__declspec(dllimport) void friend4(); // expected-warning{{redeclaration of 'friend4' should not add 'dllimport' attribute}}
__declspec(dllimport) inline void friend5() {} // expected-warning{{redeclaration of 'friend5' should not add 'dllimport' attribute}}
void __declspec(dllimport) friend6(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
void __declspec(dllimport) friend7();