From: Steve Naroff Date: Fri, 31 Aug 2007 17:20:07 +0000 (+0000) Subject: Removed Sema::VerifyConstantArrayType(). With the new Array/ConstantArray/VariableArr... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d7444aac1af1c2c1d5e5b7467ecf6006ee2d8abe;p=clang Removed Sema::VerifyConstantArrayType(). With the new Array/ConstantArray/VariableArray nodes, this routine was causing more trouble than it was worth. Anders/Chris noticed that it could return an error code without emiting a diagnostic (which results in an silent invalid decl, which should *never* happen). In addition, this routine didn't work well for typedefs and field decls. Lastly, it didn't consider that initializers aren't in place yet. Added Type::getAsConstantArrayType(), Type::getAsVariableArrayType(), Type::getAsVariablyModifiedType(), and Type::isVariablyModifiedType(); Modified Sema::ParseDeclarator() and Sema::ParseField() to use the new predicates. Also added a FIXME for the initializer omission. Also added a missing test for "static" @ file scope. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41647 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/Type.cpp b/AST/Type.cpp index 4bca030e0d..26bfbe231b 100644 --- a/AST/Type.cpp +++ b/AST/Type.cpp @@ -125,7 +125,7 @@ const ReferenceType *Type::getAsReferenceType() const { } const ArrayType *Type::getAsArrayType() const { - // If this is directly a reference type, return it. + // If this is directly an array type, return it. if (const ArrayType *ATy = dyn_cast(this)) return ATy; @@ -136,6 +136,48 @@ const ArrayType *Type::getAsArrayType() const { return 0; } +const ConstantArrayType *Type::getAsConstantArrayType() const { + // If this is directly a constant array type, return it. + if (const ConstantArrayType *ATy = dyn_cast(this)) + return ATy; + + // If this is a typedef for an array type, strip the typedef off without + // losing all typedef information. + if (isa(CanonicalType)) + return cast(cast(this)->LookThroughTypedefs()); + return 0; +} + +const VariableArrayType *Type::getAsVariableArrayType() const { + // If this is directly a variable array type, return it. + if (const VariableArrayType *ATy = dyn_cast(this)) + return ATy; + + // If this is a typedef for an array type, strip the typedef off without + // losing all typedef information. + if (isa(CanonicalType)) + return cast(cast(this)->LookThroughTypedefs()); + return 0; +} + +/// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array +/// types that have a non-constant expression. This does not include "[]". +bool Type::isVariablyModifiedType() const { + if (const VariableArrayType *VAT = getAsVariableArrayType()) { + if (VAT->getSizeExpr()) + return true; + } + return false; +} + +const VariableArrayType *Type::getAsVariablyModifiedType() const { + if (const VariableArrayType *VAT = getAsVariableArrayType()) { + if (VAT->getSizeExpr()) + return VAT; + } + return 0; +} + const RecordType *Type::getAsRecordType() const { // If this is directly a reference type, return it. if (const RecordType *RTy = dyn_cast(this)) diff --git a/Sema/Sema.h b/Sema/Sema.h index 046305ef00..a968dba88a 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -439,12 +439,6 @@ private: QualType CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc, IdentifierInfo &Comp, SourceLocation CmpLoc); - /// C99: 6.7.5p3: Used by ParseDeclarator/ParseField to make sure we have - /// a constant expression of type int with a value greater than zero. If the - /// array has an incomplete type or a valid constant size, return false, - /// otherwise emit a diagnostic and return true. - bool VerifyConstantArrayType(const ArrayType *ary, SourceLocation loc); - /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index cc0682a8da..4d2fd4d515 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -25,25 +25,6 @@ #include "llvm/ADT/SmallSet.h" using namespace clang; -// C99 6.7.2.1p8: Used by ParseDeclarator/ParseField to make sure we have -// a constant expression. We return true if we don't have a ConstantArrayType. -bool Sema::VerifyConstantArrayType(const ArrayType *Array, - SourceLocation DeclLoc) { - if (const VariableArrayType *VLA = dyn_cast(Array)) { - Expr *Size = VLA->getSizeExpr(); - if (Size) { - // FIXME: This emits the diagnostic to enforce 6.7.2.1p8, but the message - // is wrong. It is also wrong for static variables. - // FIXME: This is also wrong for: - // int sub1(int i, char *pi) { typedef int foo[i]; - // struct bar {foo f1; int f2:3; int f3:4} *p; } - Diag(DeclLoc, diag::err_typecheck_illegal_vla, Size->getSourceRange()); - } - return true; - } - return false; -} - Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const { return dyn_cast_or_null(II.getFETokenInfo()); } @@ -305,9 +286,11 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, if (S->getParent() == 0) { // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. - if (ArrayType *ary = dyn_cast(NewTD->getUnderlyingType())) { - if (VerifyConstantArrayType(ary, D.getIdentifierLoc())) - InvalidDecl = true; + if (const VariableArrayType *VAT = + NewTD->getUnderlyingType()->getAsVariablyModifiedType()) { + Diag(D.getIdentifierLoc(), diag::err_typecheck_illegal_vla, + VAT->getSizeExpr()->getSourceRange()); + InvalidDecl = true; } } } else if (D.isFunctionDeclarator()) { @@ -377,11 +360,19 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, R.getAsString()); InvalidDecl = true; } - // C99 6.7.5.2p2: If an identifier is declared to be an object with - // static storage duration, it shall not have a variable length array. - if (const ArrayType *ary = R->getAsArrayType()) { - if (VerifyConstantArrayType(ary, D.getIdentifierLoc())) - InvalidDecl = true; + if (SC == VarDecl::Static) { + // C99 6.7.5.2p2: If an identifier is declared to be an object with + // static storage duration, it shall not have a variable length array. + if (const VariableArrayType *VLA = R->getAsVariableArrayType()) { + Expr *Size = VLA->getSizeExpr(); + if (Size || (!Size && !Init)) { + // FIXME: Since we don't support initializers yet, we only emit this + // error when we don't have an initializer. Once initializers are + // implemented, the VLA will change to a CLA. + Diag(D.getIdentifierLoc(), diag::err_typecheck_illegal_vla); + InvalidDecl = true; + } + } } NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator); } else { @@ -397,9 +388,15 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, if (SC == VarDecl::Static) { // C99 6.7.5.2p2: If an identifier is declared to be an object with // static storage duration, it shall not have a variable length array. - if (const ArrayType *ary = R->getAsArrayType()) { - if (VerifyConstantArrayType(ary, D.getIdentifierLoc())) + if (const VariableArrayType *VLA = R->getAsVariableArrayType()) { + Expr *Size = VLA->getSizeExpr(); + if (Size || (!Size && !Init)) { + // FIXME: Since we don't support initializers yet, we only emit this + // error when we don't have an initializer. Once initializers are + // implemented, the VLA will change to a CLA. + Diag(D.getIdentifierLoc(), diag::err_typecheck_illegal_vla); InvalidDecl = true; + } } } NewVD = new BlockVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator); @@ -779,14 +776,14 @@ Sema::DeclTy *Sema::ParseField(Scope *S, DeclTy *TagDecl, QualType T = GetTypeForDeclarator(D, S); assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); bool InvalidDecl = false; - + // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. - if (const ArrayType *ary = T->getAsArrayType()) { - if (VerifyConstantArrayType(ary, Loc)) - InvalidDecl = true; + if (const VariableArrayType *VAT = T->getAsVariablyModifiedType()) { + Diag(Loc, diag::err_typecheck_illegal_vla, + VAT->getSizeExpr()->getSourceRange()); + InvalidDecl = true; } - // FIXME: Chain fielddecls together. FieldDecl *NewFD = new FieldDecl(Loc, II, T, 0); if (D.getInvalidType() || InvalidDecl) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index a8fb40699b..b58652cd0d 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -37,6 +37,8 @@ namespace clang { class ReferenceType; class VectorType; class ArrayType; + class ConstantArrayType; + class VariableArrayType; class RecordType; class ComplexType; class TagType; @@ -233,6 +235,10 @@ public: /// routine will need to determine if the size is actually required. bool isIncompleteType() const; + /// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array + /// types that have a non-constant expression. This does not include "[]". + bool isVariablyModifiedType() const; + /// Helper methods to distinguish type categories. All type predicates /// operate on the canonical type, ignoring typedefs. bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) @@ -271,6 +277,9 @@ public: const PointerType *getAsPointerType() const; const ReferenceType *getAsReferenceType() const; const ArrayType *getAsArrayType() const; + const ConstantArrayType *getAsConstantArrayType() const; + const VariableArrayType *getAsVariableArrayType() const; + const VariableArrayType *getAsVariablyModifiedType() const; const RecordType *getAsRecordType() const; const RecordType *getAsStructureType() const; const RecordType *getAsUnionType() const; diff --git a/test/Sema/array-constraint.c b/test/Sema/array-constraint.c index 1ca3cd7aec..867d4e7cbf 100644 --- a/test/Sema/array-constraint.c +++ b/test/Sema/array-constraint.c @@ -39,3 +39,13 @@ void check_size() { int zero_size[0]; // expected-warning{{zero size arrays are an extension}} } +static int I; +typedef int TA[I]; // expected-error {{variable length array declared outside of any function}} + +void strFunc(char *); +const char staticAry[] = "test"; +int checkStaticAry() { + strFunc(staticAry); // expected-warning{{passing 'char const []' to 'char *' discards qualifiers}} +} + +