From: Steve Naroff Date: Wed, 30 Jan 2008 00:44:01 +0000 (+0000) Subject: Many refinements to Sema::MergeVarDecl(). This routine still needs some re-work to... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b7b032ecb23e5a2ebff89d62478f93313c04d367;p=clang Many refinements to Sema::MergeVarDecl(). This routine still needs some re-work to fully handle tentative decls. This includes a fix to bz1908. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46540 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 9dd306944d..68177e03c8 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -319,26 +319,56 @@ VarDecl *Sema::MergeVarDecl(VarDecl *New, ScopedDecl *OldD) { Diag(OldD->getLocation(), diag::err_previous_definition); return New; } + // Verify the types match. + if (Old->getCanonicalType() != New->getCanonicalType() && + !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) { + Diag(New->getLocation(), diag::err_redefinition, New->getName()); + Diag(Old->getLocation(), diag::err_previous_definition); + return New; + } + // C99 6.2.2p4: Check if we have a static decl followed by a non-static. + if (New->getStorageClass() == VarDecl::Static && + (Old->getStorageClass() == VarDecl::None || + Old->getStorageClass() == VarDecl::Extern)) { + Diag(New->getLocation(), diag::err_static_non_static, New->getName()); + Diag(Old->getLocation(), diag::err_previous_definition); + return New; + } + // C99 6.2.2p4: Check if we have a non-static decl followed by a static. + if (New->getStorageClass() != VarDecl::Static && + Old->getStorageClass() == VarDecl::Static) { + Diag(New->getLocation(), diag::err_non_static_static, New->getName()); + Diag(Old->getLocation(), diag::err_previous_definition); + return New; + } + // We've verified the types match, now handle "tentative" definitions. FileVarDecl *OldFSDecl = dyn_cast(Old); FileVarDecl *NewFSDecl = dyn_cast(New); - bool OldIsTentative = false; - if (OldFSDecl && NewFSDecl) { // C99 6.9.2 - // Handle C "tentative" external object definitions. FIXME: finish! + if (OldFSDecl && NewFSDecl) { + // Handle C "tentative" external object definitions (C99 6.9.2). + bool OldIsTentative = false; + bool NewIsTentative = false; + if (!OldFSDecl->getInit() && (OldFSDecl->getStorageClass() == VarDecl::None || OldFSDecl->getStorageClass() == VarDecl::Static)) OldIsTentative = true; + + // FIXME: this check doesn't work (since the initializer hasn't been + // attached yet). This check should be moved to FinalizeDeclaratorGroup. + // Unfortunately, by the time we get to FinializeDeclaratorGroup, we've + // thrown out the old decl. + if (!NewFSDecl->getInit() && + (NewFSDecl->getStorageClass() == VarDecl::None || + NewFSDecl->getStorageClass() == VarDecl::Static)) + ; // change to NewIsTentative = true; once the code is moved. + + if (NewIsTentative || OldIsTentative) + return New; } - // Verify the types match. - if (Old->getCanonicalType() != New->getCanonicalType() && - !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) { - Diag(New->getLocation(), diag::err_redefinition, New->getName()); - Diag(Old->getLocation(), diag::err_previous_definition); - return New; - } - // We've verified the types match, now check if Old is "extern". - if (Old->getStorageClass() != VarDecl::Extern) { + if (Old->getStorageClass() != VarDecl::Extern && + New->getStorageClass() != VarDecl::Extern) { Diag(New->getLocation(), diag::err_redefinition, New->getName()); Diag(Old->getLocation(), diag::err_previous_definition); } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index ad628af24f..83e9e84dce 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -602,6 +602,10 @@ DIAG(err_undeclared_var_use, ERROR, "use of undeclared identifier '%0'") DIAG(err_redefinition, ERROR, "redefinition of '%0'") +DIAG(err_static_non_static, ERROR, + "static declaration of '%0' follows non-static declaration") +DIAG(err_non_static_static, ERROR, + "non-static declaration of '%0' follows static declaration") DIAG(err_redefinition_different_kind, ERROR, "redefinition of '%0' as different kind of symbol") DIAG(err_conflicting_types, ERROR, diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c new file mode 100644 index 0000000000..0c390fe414 --- /dev/null +++ b/test/Sema/tentative-decls.c @@ -0,0 +1,24 @@ +// RUN: clang %s -verify -fsyntax-only + +const int a [1] = {1}; +extern const int a[]; + +extern const int b[]; +const int b [1] = {1}; + +extern const int c[] = {1}; // expected-warning{{'extern' variable has an initializer}} +const int c[]; + +int i1 = 1; // expected-error{{previous definition is here}} +int i1 = 2; // expected-error{{redefinition of 'i1'}} // expected-error{{previous definition is here}} +// FIXME: the following should not be an error (see related FIXME in Sema::MergeVarDecl). +int i1; // expected-error{{redefinition of 'i1'}} +int i1; +extern int i1; // expected-error{{previous definition is here}} +static int i1; // expected-error{{static declaration of 'i1' follows non-static declaration}} expected-error{{previous definition is here}} +int i1 = 3; // expected-error{{non-static declaration of 'i1' follows static declaration}} + +void func() { + extern int i1; // expected-error{{previous definition is here}} + static int i1; // expected-error{{static declaration of 'i1' follows non-static declaration}} +}