aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AST/Type.cpp44
-rw-r--r--Sema/Sema.h6
-rw-r--r--Sema/SemaDecl.cpp65
-rw-r--r--include/clang/AST/Type.h9
-rw-r--r--test/Sema/array-constraint.c10
5 files changed, 93 insertions, 41 deletions
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<ArrayType>(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<ConstantArrayType>(this))
+ return ATy;
+
+ // If this is a typedef for an array type, strip the typedef off without
+ // losing all typedef information.
+ if (isa<ConstantArrayType>(CanonicalType))
+ return cast<ConstantArrayType>(cast<TypedefType>(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<VariableArrayType>(this))
+ return ATy;
+
+ // If this is a typedef for an array type, strip the typedef off without
+ // losing all typedef information.
+ if (isa<VariableArrayType>(CanonicalType))
+ return cast<VariableArrayType>(cast<TypedefType>(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<RecordType>(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<VariableArrayType>(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<TypedefDecl>(II.getFETokenInfo<Decl>());
}
@@ -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<ArrayType>(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}}
+}
+
+