mirror of https://github.com/microsoft/clang.git
Sema: Static redeclaration after extern declarations is a Microsoft Extension
CL permits static redeclarations to follow extern declarations. The storage specifier on the latter declaration has no effect. This fixes PR20034. Differential Revision: http://reviews.llvm.org/D4149 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211238 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e15ff8e771
commit
2e01479f1c
|
@ -3814,8 +3814,8 @@ def note_extern_c_global_conflict : Note<
|
|||
"declared %select{in global scope|with C language linkage}0 here">;
|
||||
def warn_weak_import : Warning <
|
||||
"an already-declared variable is made a weak_import declaration %0">;
|
||||
def warn_static_non_static : ExtWarn<
|
||||
"static declaration of %0 follows non-static declaration">;
|
||||
def ext_static_non_static : Extension<
|
||||
"redeclaring non-static %0 as static is a Microsoft extension">, InGroup<Microsoft>;
|
||||
def err_non_static_static : Error<
|
||||
"non-static declaration of %0 follows static declaration">;
|
||||
def err_extern_non_extern : Error<
|
||||
|
|
|
@ -2253,6 +2253,24 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
|
|||
return Sema::CXXInvalid;
|
||||
}
|
||||
|
||||
// Determine whether the previous declaration was a definition, implicit
|
||||
// declaration, or a declaration.
|
||||
template <typename T>
|
||||
static std::pair<diag::kind, SourceLocation>
|
||||
getNoteDiagForInvalidRedeclaration(const T *Old, const T *New) {
|
||||
diag::kind PrevDiag;
|
||||
SourceLocation OldLocation = Old->getLocation();
|
||||
if (Old->isThisDeclarationADefinition())
|
||||
PrevDiag = diag::note_previous_definition;
|
||||
else if (Old->isImplicit()) {
|
||||
PrevDiag = diag::note_previous_implicit_declaration;
|
||||
if (OldLocation.isInvalid())
|
||||
OldLocation = New->getLocation();
|
||||
} else
|
||||
PrevDiag = diag::note_previous_declaration;
|
||||
return std::make_pair(PrevDiag, OldLocation);
|
||||
}
|
||||
|
||||
/// canRedefineFunction - checks if a function can be redefined. Currently,
|
||||
/// only extern inline functions can be redefined, and even then only in
|
||||
/// GNU89 mode.
|
||||
|
@ -2345,18 +2363,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
|
|||
if (Old->isInvalidDecl())
|
||||
return true;
|
||||
|
||||
// Determine whether the previous declaration was a definition,
|
||||
// implicit declaration, or a declaration.
|
||||
diag::kind PrevDiag;
|
||||
SourceLocation OldLocation = Old->getLocation();
|
||||
if (Old->isThisDeclarationADefinition())
|
||||
PrevDiag = diag::note_previous_definition;
|
||||
else if (Old->isImplicit()) {
|
||||
PrevDiag = diag::note_previous_implicit_declaration;
|
||||
if (OldLocation.isInvalid())
|
||||
OldLocation = New->getLocation();
|
||||
} else
|
||||
PrevDiag = diag::note_previous_declaration;
|
||||
SourceLocation OldLocation;
|
||||
std::tie(PrevDiag, OldLocation) =
|
||||
getNoteDiagForInvalidRedeclaration(Old, New);
|
||||
|
||||
// Don't complain about this if we're in GNU89 mode and the old function
|
||||
// is an extern inline function.
|
||||
|
@ -2368,7 +2378,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
|
|||
!New->getTemplateSpecializationInfo() &&
|
||||
!canRedefineFunction(Old, getLangOpts())) {
|
||||
if (getLangOpts().MicrosoftExt) {
|
||||
Diag(New->getLocation(), diag::warn_static_non_static) << New;
|
||||
Diag(New->getLocation(), diag::ext_static_non_static) << New;
|
||||
Diag(OldLocation, PrevDiag);
|
||||
} else {
|
||||
Diag(New->getLocation(), diag::err_static_non_static) << New;
|
||||
|
@ -3069,13 +3079,25 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
if (New->isInvalidDecl())
|
||||
return;
|
||||
|
||||
diag::kind PrevDiag;
|
||||
SourceLocation OldLocation;
|
||||
std::tie(PrevDiag, OldLocation) =
|
||||
getNoteDiagForInvalidRedeclaration(Old, New);
|
||||
|
||||
// [dcl.stc]p8: Check if we have a non-static decl followed by a static.
|
||||
if (New->getStorageClass() == SC_Static &&
|
||||
!New->isStaticDataMember() &&
|
||||
Old->hasExternalFormalLinkage()) {
|
||||
Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
return New->setInvalidDecl();
|
||||
if (getLangOpts().MicrosoftExt) {
|
||||
Diag(New->getLocation(), diag::ext_static_non_static)
|
||||
<< New->getDeclName();
|
||||
Diag(OldLocation, PrevDiag);
|
||||
} else {
|
||||
Diag(New->getLocation(), diag::err_static_non_static)
|
||||
<< New->getDeclName();
|
||||
Diag(OldLocation, PrevDiag);
|
||||
return New->setInvalidDecl();
|
||||
}
|
||||
}
|
||||
// C99 6.2.2p4:
|
||||
// For an identifier declared with the storage-class specifier
|
||||
|
@ -3092,7 +3114,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
!New->isStaticDataMember() &&
|
||||
Old->getCanonicalDecl()->getStorageClass() == SC_Static) {
|
||||
Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
Diag(OldLocation, PrevDiag);
|
||||
return New->setInvalidDecl();
|
||||
}
|
||||
|
||||
|
@ -3100,13 +3122,13 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
if (New->hasExternalStorage() &&
|
||||
!Old->hasLinkage() && Old->isLocalVarDecl()) {
|
||||
Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
Diag(OldLocation, PrevDiag);
|
||||
return New->setInvalidDecl();
|
||||
}
|
||||
if (Old->hasLinkage() && New->isLocalVarDecl() &&
|
||||
!New->hasExternalStorage()) {
|
||||
Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
Diag(OldLocation, PrevDiag);
|
||||
return New->setInvalidDecl();
|
||||
}
|
||||
|
||||
|
@ -3119,17 +3141,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
!(Old->getLexicalDeclContext()->isRecord() &&
|
||||
!New->getLexicalDeclContext()->isRecord())) {
|
||||
Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
Diag(OldLocation, PrevDiag);
|
||||
return New->setInvalidDecl();
|
||||
}
|
||||
|
||||
if (New->getTLSKind() != Old->getTLSKind()) {
|
||||
if (!Old->getTLSKind()) {
|
||||
Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||
Diag(OldLocation, PrevDiag);
|
||||
} else if (!New->getTLSKind()) {
|
||||
Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||
Diag(OldLocation, PrevDiag);
|
||||
} else {
|
||||
// Do not allow redeclaration to change the variable between requiring
|
||||
// static and dynamic initialization.
|
||||
|
@ -3137,7 +3159,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
// declaration to determine the kind. Do we need to be compatible here?
|
||||
Diag(New->getLocation(), diag::err_thread_thread_different_kind)
|
||||
<< New->getDeclName() << (New->getTLSKind() == VarDecl::TLS_Dynamic);
|
||||
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||
Diag(OldLocation, PrevDiag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3154,7 +3176,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
|
||||
if (haveIncompatibleLanguageLinkages(Old, New)) {
|
||||
Diag(New->getLocation(), diag::err_different_language_linkage) << New;
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
Diag(OldLocation, PrevDiag);
|
||||
New->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ This test serves two purposes:
|
|||
|
||||
The list of warnings below should NEVER grow. It should gradually shrink to 0.
|
||||
|
||||
CHECK: Warnings without flags (106):
|
||||
CHECK: Warnings without flags (105):
|
||||
CHECK-NEXT: ext_delete_void_ptr_operand
|
||||
CHECK-NEXT: ext_expected_semi_decl_list
|
||||
CHECK-NEXT: ext_explicit_specialization_storage_class
|
||||
|
@ -114,7 +114,6 @@ CHECK-NEXT: warn_redeclaration_without_attribute_prev_attribute_ignored
|
|||
CHECK-NEXT: warn_register_objc_catch_parm
|
||||
CHECK-NEXT: warn_related_result_type_compatibility_class
|
||||
CHECK-NEXT: warn_related_result_type_compatibility_protocol
|
||||
CHECK-NEXT: warn_static_non_static
|
||||
CHECK-NEXT: warn_template_export_unsupported
|
||||
CHECK-NEXT: warn_template_spec_extra_headers
|
||||
CHECK-NEXT: warn_tentative_incomplete_array
|
||||
|
|
|
@ -13,10 +13,10 @@ __private_extern__ int g2;
|
|||
int g3; // expected-note{{previous definition}}
|
||||
static int g3; // expected-error{{static declaration of 'g3' follows non-static declaration}}
|
||||
|
||||
extern int g4; // expected-note{{previous definition}}
|
||||
extern int g4; // expected-note{{previous declaration}}
|
||||
static int g4; // expected-error{{static declaration of 'g4' follows non-static declaration}}
|
||||
|
||||
__private_extern__ int g5; // expected-note{{previous definition}}
|
||||
__private_extern__ int g5; // expected-note{{previous declaration}}
|
||||
static int g5; // expected-error{{static declaration of 'g5' follows non-static declaration}}
|
||||
|
||||
void f0() {
|
||||
|
@ -30,12 +30,12 @@ void f1() {
|
|||
}
|
||||
|
||||
void f2() {
|
||||
extern int g8; // expected-note{{previous definition}}
|
||||
extern int g8; // expected-note{{previous declaration}}
|
||||
int g8; // expected-error {{non-extern declaration of 'g8' follows extern declaration}}
|
||||
}
|
||||
|
||||
void f3() {
|
||||
__private_extern__ int g9; // expected-note{{previous definition}}
|
||||
__private_extern__ int g9; // expected-note{{previous declaration}}
|
||||
int g9; // expected-error {{non-extern declaration of 'g9' follows extern declaration}}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ int i1 = 1; // expected-note {{previous definition is here}}
|
|||
int i1 = 2; // expected-error {{redefinition of 'i1'}}
|
||||
int i1;
|
||||
int i1;
|
||||
extern int i5; // expected-note {{previous definition is here}}
|
||||
extern int i5; // expected-note {{previous declaration is here}}
|
||||
static int i5; // expected-error{{static declaration of 'i5' follows non-static declaration}}
|
||||
|
||||
static int i2 = 5; // expected-note 1 {{previous definition is here}}
|
||||
|
@ -49,7 +49,7 @@ int redef[]; // expected-note {{previous definition is here}}
|
|||
int redef[11]; // expected-error{{redefinition of 'redef'}}
|
||||
|
||||
void func() {
|
||||
extern int i6; // expected-note {{previous definition is here}}
|
||||
extern int i6; // expected-note {{previous declaration is here}}
|
||||
static int i6; // expected-error{{static declaration of 'i6' follows non-static declaration}}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ int f(__thread int t7) { // expected-error {{' is only allowed on variable decla
|
|||
}
|
||||
|
||||
__thread typedef int t14; // expected-error-re {{cannot combine with previous '{{__thread|_Thread_local|thread_local}}' declaration specifier}}
|
||||
__thread int t15; // expected-note {{previous declaration is here}}
|
||||
__thread int t15; // expected-note {{previous definition is here}}
|
||||
extern int t15; // expected-error {{non-thread-local declaration of 't15' follows thread-local declaration}}
|
||||
extern int t16; // expected-note {{previous declaration is here}}
|
||||
__thread int t16; // expected-error {{thread-local declaration of 't16' follows non-thread-local declaration}}
|
||||
|
|
|
@ -58,5 +58,5 @@ int *p=&g19; // expected-error{{use of undeclared identifier 'g19'}} \
|
|||
|
||||
// PR3645
|
||||
static int a;
|
||||
extern int a; // expected-note {{previous definition is here}}
|
||||
extern int a; // expected-note {{previous declaration is here}}
|
||||
int a; // expected-error {{non-static declaration of 'a' follows static declaration}}
|
||||
|
|
|
@ -144,11 +144,14 @@ extern void static_func();
|
|||
void static_func(); // expected-note {{previous declaration is here}}
|
||||
|
||||
|
||||
static void static_func() // expected-warning {{static declaration of 'static_func' follows non-static declaration}}
|
||||
static void static_func() // expected-warning {{redeclaring non-static 'static_func' as static is a Microsoft extension}}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
extern const int static_var; // expected-note {{previous declaration is here}}
|
||||
static const int static_var = 3; // expected-warning {{redeclaring non-static 'static_var' as static is a Microsoft extension}}
|
||||
|
||||
long function_prototype(int a);
|
||||
long (*function_ptr)(int a);
|
||||
|
||||
|
|
Loading…
Reference in New Issue