aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-07-20 18:46:59 +0000
committerDouglas Gregor <dgregor@apple.com>2009-07-20 18:46:59 +0000
commitec8b59ffc30c65051070e6d6cbb8e4b419210d18 (patch)
treea2521d2b58760bd1b6fcdc1ae59aa9dc9a5510a8
parent520035439d7133064325c4df6378c5a8f2f05539 (diff)
Improve GCC compatibility by allowing static tentative definitions of
incomplete type (with a warning), from Enea Zaffanella! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76451 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/SemaDecl.cpp35
-rw-r--r--test/Sema/incomplete-decl.c5
-rw-r--r--test/Sema/tentative-decls.c2
4 files changed, 25 insertions, 19 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 7fc237bf0b..2864ed2ad6 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1206,6 +1206,8 @@ def err_typecheck_pointer_arith_void_type : Error<
"arithmetic on pointer to void type">;
def err_typecheck_decl_incomplete_type : Error<
"variable has incomplete type %0">;
+def ext_typecheck_decl_incomplete_type : ExtWarn<
+ "tentative definition of variable with internal linkage has incomplete non-array type %0">;
def err_tentative_def_incomplete_type : Error<
"tentative definition has type %0 that is never completed">;
def err_tentative_def_incomplete_type_arr : Error<
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 28ac9d1982..d1d06e3284 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2899,29 +2899,32 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
diag::err_typecheck_decl_incomplete_type))
IDecl->setInvalidDecl();
}
- // File scope. C99 6.9.2p2: A declaration of an identifier for and
+ // File scope. C99 6.9.2p2: A declaration of an identifier for an
// object that has file scope without an initializer, and without a
// storage-class specifier or with the storage-class specifier "static",
// constitutes a tentative definition. Note: A tentative definition with
// external linkage is valid (C99 6.2.2p5).
- if (IDecl->isTentativeDefinition(Context)) {
- QualType CheckType = T;
- unsigned DiagID = diag::err_typecheck_decl_incomplete_type;
-
- const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(T);
- if (ArrayT) {
- CheckType = ArrayT->getElementType();
- DiagID = diag::err_illegal_decl_array_incomplete_type;
+ if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) {
+ if (const IncompleteArrayType *ArrayT
+ = Context.getAsIncompleteArrayType(T)) {
+ if (RequireCompleteType(IDecl->getLocation(),
+ ArrayT->getElementType(),
+ diag::err_illegal_decl_array_incomplete_type))
+ IDecl->setInvalidDecl();
}
-
- if (IDecl->isInvalidDecl()) {
- // Do nothing with invalid declarations
- } else if ((ArrayT || IDecl->getStorageClass() == VarDecl::Static) &&
- RequireCompleteType(IDecl->getLocation(), CheckType, DiagID)) {
+ else if (IDecl->getStorageClass() == VarDecl::Static) {
// C99 6.9.2p3: If the declaration of an identifier for an object is
- // a tentative definition and has internal linkage (C99 6.2.2p3), the
+ // a tentative definition and has internal linkage (C99 6.2.2p3), the
// declared type shall not be an incomplete type.
- IDecl->setInvalidDecl();
+ // NOTE: code such as the following
+ // static struct s;
+ // struct s { int a; };
+ // is accepted by gcc. Hence here we issue a warning instead of
+ // an error and we do not invalidate the static declaration.
+ // NOTE: to avoid multiple warnings, only check the first declaration.
+ if (IDecl->getPreviousDeclaration() == 0)
+ RequireCompleteType(IDecl->getLocation(), T,
+ diag::ext_typecheck_decl_incomplete_type);
}
}
}
diff --git a/test/Sema/incomplete-decl.c b/test/Sema/incomplete-decl.c
index eb93e8e380..6a6ba753f3 100644
--- a/test/Sema/incomplete-decl.c
+++ b/test/Sema/incomplete-decl.c
@@ -1,12 +1,13 @@
// RUN: clang-cc -fsyntax-only -verify %s
-struct foo; // expected-note 4 {{forward declaration of 'struct foo'}}
+struct foo; // expected-note 5 {{forward declaration of 'struct foo'}}
void b; // expected-error {{variable has incomplete type 'void'}}
struct foo f; // expected-error{{tentative definition has type 'struct foo' that is never completed}}
static void c; // expected-error {{variable has incomplete type 'void'}}
-static struct foo g; // expected-error {{variable has incomplete type 'struct foo'}}
+static struct foo g; // expected-warning {{tentative definition of variable with internal linkage has incomplete non-array type 'struct foo'}} \
+ expected-error{{tentative definition has type 'struct foo' that is never completed}}
extern void d;
extern struct foo e;
diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c
index e3c893c777..c94af1160b 100644
--- a/test/Sema/tentative-decls.c
+++ b/test/Sema/tentative-decls.c
@@ -2,7 +2,7 @@
// PR3310
struct a x1; // expected-note 2{{forward declaration of 'struct a'}}
-static struct a x2; // expected-error{{variable has incomplete type 'struct a'}}
+static struct a x2; // expected-warning{{tentative definition of variable with internal linkage has incomplete non-array type 'struct a'}}
struct a x3[10]; // expected-error{{array has incomplete element type 'struct a'}}
struct a {int x;};
static struct a x2_okay;