diff options
| author | Eli Friedman <eli.friedman@gmail.com> | 2009-02-21 00:44:51 +0000 |
|---|---|---|
| committer | Eli Friedman <eli.friedman@gmail.com> | 2009-02-21 00:44:51 +0000 |
| commit | a3b1d03e2d70a1ef915a5fcd7ef8269064897e5b (patch) | |
| tree | 068f4d881151d2ffe5ed143d366a4a5e69e99081 /clang/lib/Sema | |
| parent | 56759ee65882d38b4d95af96edd2393efcacbfee (diff) | |
| download | bcm5719-llvm-a3b1d03e2d70a1ef915a5fcd7ef8269064897e5b.tar.gz bcm5719-llvm-a3b1d03e2d70a1ef915a5fcd7ef8269064897e5b.zip | |
Re-fix r65140 correctly.
llvm-svn: 65208
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 79 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 16 |
2 files changed, 72 insertions, 23 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index dfa1e031779..faaa5290962 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1412,6 +1412,44 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl, return New; } +/// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array +/// types into constant array types in certain situations which would otherwise +/// be errors (for GCC compatibility). +static QualType TryToFixInvalidVariablyModifiedType(QualType T, + ASTContext &Context, + bool &SizeIsNegative) { + // This method tries to turn a variable array into a constant + // array even when the size isn't an ICE. This is necessary + // for compatibility with code that depends on gcc's buggy + // constant expression folding, like struct {char x[(int)(char*)2];} + SizeIsNegative = false; + + if (const PointerType* PTy = dyn_cast<PointerType>(T)) { + QualType Pointee = PTy->getPointeeType(); + QualType FixedType = + TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative); + if (FixedType.isNull()) return FixedType; + return Context.getPointerType(FixedType); + } + + const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T); + if (!VLATy) return QualType(); + + Expr::EvalResult EvalResult; + if (!VLATy->getSizeExpr() || + !VLATy->getSizeExpr()->Evaluate(EvalResult, Context)) + return QualType(); + + assert(EvalResult.Val.isInt() && "Size expressions must be integers!"); + llvm::APSInt &Res = EvalResult.Val.getInt(); + if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) + return Context.getConstantArrayType(VLATy->getElementType(), + Res, ArrayType::Normal, 0); + + SizeIsNegative = true; + return QualType(); +} + NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, Decl* LastDeclarator, @@ -1444,15 +1482,25 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, } if (S->getFnParent() == 0) { + QualType T = NewTD->getUnderlyingType(); // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. - if (NewTD->getUnderlyingType()->isVariablyModifiedType()) { - if (NewTD->getUnderlyingType()->isVariableArrayType()) - Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope); - else - Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope); - - InvalidDecl = true; + if (T->isVariablyModifiedType()) { + bool SizeIsNegative; + QualType FixedTy = + TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); + if (!FixedTy.isNull()) { + Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); + NewTD->setUnderlyingType(FixedTy); + } else { + if (SizeIsNegative) + Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); + else if (T->isVariableArrayType()) + Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope); + else + Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope); + InvalidDecl = true; + } } } return NewTD; @@ -3449,9 +3497,20 @@ Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD, // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. if (T->isVariablyModifiedType()) { - Diag(Loc, diag::err_typecheck_field_variable_size); - T = Context.IntTy; - InvalidDecl = true; + bool SizeIsNegative; + QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, + SizeIsNegative); + if (!FixedTy.isNull()) { + Diag(Loc, diag::warn_illegal_constant_array_size); + T = FixedTy; + } else { + if (SizeIsNegative) + Diag(Loc, diag::err_typecheck_negative_array_size); + else + Diag(Loc, diag::err_typecheck_field_variable_size); + T = Context.IntTy; + InvalidDecl = true; + } } if (BitWidth) { diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 8727fbcd8cc..252cd2d533c 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -423,26 +423,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { ArraySize->Destroy(Context); ATI.NumElts = ArraySize = 0; } - Expr::EvalResult Result; + llvm::APSInt ConstVal(32); if (!ArraySize) { T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals); } else if (ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, ATI.TypeQuals); - } else if (!ArraySize->Evaluate(Result, Context) || + } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || !T->isConstantSizeType()) { // Per C99, a variable array is an array with either a non-constant // size or an element type that has a non-constant-size T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals); } else { - const llvm::APSInt& ConstVal = Result.Val.getInt(); - - // FIXME: We should really use Result.Diag here - which is supposed - // to be nonzero if we have a foldable expression that is not an ICE - // but for now we'll just warn if the array size is not an ICE. - if (!ArraySize->isIntegerConstantExpr(Context)) - Diag(ArraySize->getLocStart(), - diag::warn_illegal_constant_array_size); - // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. if (ConstVal.isSigned()) { @@ -453,8 +444,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { D.setInvalidType(true); } else if (ConstVal == 0) { // GCC accepts zero sized static arrays. - Diag(ArraySize->getLocStart(), - diag::ext_typecheck_zero_array_size) + Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) << ArraySize->getSourceRange(); } } |

