From fcc2d26e73192634dd05fb1b6800b5a063432feb Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 6 Nov 2007 04:28:31 +0000 Subject: [PATCH] Add better validation for array types when merging decls. Patch contributed by Oliver Hunt, thanks! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43750 91177308-0d34-0410-b5e6-96231b3b80d8 --- Sema/SemaDecl.cpp | 42 +++++++++++++++++++- test/Sema/array-declared-as-incorrect-type.c | 16 ++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 test/Sema/array-declared-as-incorrect-type.c diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 437ec30930..40414b46cd 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -254,6 +254,45 @@ FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, ScopedDecl *OldD) { return New; } + +/// hasUndefinedLength - Used by equivalentArrayTypes to determine whether the +/// the outermost VariableArrayType has no size defined. +static bool hasUndefinedLength(const ArrayType *Array) { + const VariableArrayType *VAT = Array->getAsVariableArrayType(); + return VAT && !VAT->getSizeExpr(); +} + +/// equivalentArrayTypes - Used to determine whether two array types are +/// equivalent. +/// We need to check this explicitly as an incomplete array definition is +/// considered a VariableArrayType, so will not match a complete array +/// definition that would be otherwise equivalent. +static bool areEquivalentArrayTypes(QualType NewQType, QualType OldQType) { + const ArrayType *NewAT = NewQType->getAsArrayType(); + const ArrayType *OldAT = OldQType->getAsArrayType(); + + if (!NewAT || !OldAT) + return false; + + // If either (or both) array types in incomplete we need to strip off the + // outer VariableArrayType. Once the outer VAT is removed the remaining + // types must be identical if the array types are to be considered + // equivalent. + // eg. int[][1] and int[1][1] become + // VAT(null, CAT(1, int)) and CAT(1, CAT(1, int)) + // removing the outermost VAT gives + // CAT(1, int) and CAT(1, int) + // which are equal, therefore the array types are equivalent. + if (hasUndefinedLength(NewAT) || hasUndefinedLength(OldAT)) { + if (NewAT->getIndexTypeQualifier() != OldAT->getIndexTypeQualifier()) + return false; + NewQType = NewAT->getElementType(); + OldQType = OldAT->getElementType(); + } + + return NewQType == OldQType; +} + /// MergeVarDecl - We just parsed a variable 'New' which has the same name /// and scope as a previous declaration 'Old'. Figure out how to resolve this /// situation, merging decls or emitting diagnostics as appropriate. @@ -282,7 +321,8 @@ VarDecl *Sema::MergeVarDecl(VarDecl *New, ScopedDecl *OldD) { OldIsTentative = true; } // Verify the types match. - if (Old->getCanonicalType() != New->getCanonicalType()) { + 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; diff --git a/test/Sema/array-declared-as-incorrect-type.c b/test/Sema/array-declared-as-incorrect-type.c new file mode 100644 index 0000000000..e7dd458dc0 --- /dev/null +++ b/test/Sema/array-declared-as-incorrect-type.c @@ -0,0 +1,16 @@ +// RUN: clang -fsyntax-only -verify -pedantic %s + +extern int a1[]; +int a1[1]; + +extern int a2[]; // expected-error {{previous definition is here}} +float a2[1]; // expected-error {{redefinition of 'a2'}} + +extern int a3[][2]; +int a3[1][2]; + +extern int a4[][2]; // expected-error {{previous definition is here}} +int a4[2]; // expected-error {{redefinition of 'a4'}} + +extern int a5[1][2][3]; // expected-error {{previous definition is here}} +int a5[3][2][1]; // expected-error {{redefinition of 'a5'}} -- 2.40.0