From: Eli Friedman Date: Sat, 21 Feb 2009 00:44:51 +0000 (+0000) Subject: Re-fix r65140 correctly. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1ca4813ddae54deead43252fe2f2d79fa5b7ad48;p=clang Re-fix r65140 correctly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65208 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index dfa1e03177..faaa529096 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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(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(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/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8727fbcd8c..252cd2d533 100644 --- a/lib/Sema/SemaType.cpp +++ b/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(); } }