diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-08-18 00:39:00 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-08-18 00:39:00 +0000 |
commit | 2767ce2e21d8bc17869b8436220bce719b3369e4 (patch) | |
tree | da28a287f95cc22f3f3e6a8260aed48f359c3692 /lib/Sema/SemaDecl.cpp | |
parent | 5990b5455b5e309a029a6a44889ded4e9d549f24 (diff) |
Emit an error if an array is too large. We're slightly more strict
than GCC 4.2 here when building 32-bit (where GCC will allow
allocation of an array for which we can't get a valid past-the-end
pointer), and emulate its odd behavior in 64-bit where it only allows
63 bits worth of storage in the array. The former is a correctness
issue; the latter is harmless in practice (you wouldn't be able to use
such an array anyway) and helps us pass a GCC DejaGNU test.
Fixes <rdar://problem/8212293>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111338 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 51 |
1 files changed, 39 insertions, 12 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 550dcb8aeb..dfbc7e1559 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2364,20 +2364,26 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, /// be errors (for GCC compatibility). static QualType TryToFixInvalidVariablyModifiedType(QualType T, ASTContext &Context, - bool &SizeIsNegative) { + bool &SizeIsNegative, + llvm::APSInt &Oversized) { // 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; - + Oversized = 0; + + if (T->isDependentType()) + return QualType(); + QualifierCollector Qs; const Type *Ty = Qs.strip(T); if (const PointerType* PTy = dyn_cast<PointerType>(Ty)) { QualType Pointee = PTy->getPointeeType(); QualType FixedType = - TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative); + TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative, + Oversized); if (FixedType.isNull()) return FixedType; FixedType = Context.getPointerType(FixedType); return Qs.apply(FixedType); @@ -2396,15 +2402,24 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, !EvalResult.Val.isInt()) return QualType(); + // Check whether the array size is negative. llvm::APSInt &Res = EvalResult.Val.getInt(); - if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) { - // TODO: preserve the size expression in declarator info - return Context.getConstantArrayType(VLATy->getElementType(), - Res, ArrayType::Normal, 0); + if (Res.isSigned() && Res.isNegative()) { + SizeIsNegative = true; + return QualType(); } - SizeIsNegative = true; - return QualType(); + // Check whether the array is too large to be addressed. + unsigned ActiveSizeBits + = ConstantArrayType::getNumAddressingBits(Context, VLATy->getElementType(), + Res); + if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { + Oversized = Res; + return QualType(); + } + + return Context.getConstantArrayType(VLATy->getElementType(), + Res, ArrayType::Normal, 0); } /// \brief Register the given locally-scoped external C declaration so @@ -2501,8 +2516,10 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (S->getFnParent() == 0) { bool SizeIsNegative; + llvm::APSInt Oversized; QualType FixedTy = - TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); + TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, + Oversized); if (!FixedTy.isNull()) { Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy)); @@ -2511,6 +2528,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); else if (T->isVariableArrayType()) Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope); + else if (Oversized.getBoolValue()) + Diag(D.getIdentifierLoc(), diag::err_array_too_large) + << Oversized.toString(10); else Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope); NewTD->setInvalidDecl(); @@ -2931,8 +2951,10 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, if ((isVM && NewVD->hasLinkage()) || (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { bool SizeIsNegative; + llvm::APSInt Oversized; QualType FixedTy = - TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); + TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, + Oversized); if (FixedTy.isNull() && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); @@ -5965,14 +5987,19 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // than a variably modified type. if (!InvalidDecl && T->isVariablyModifiedType()) { bool SizeIsNegative; + llvm::APSInt Oversized; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, - SizeIsNegative); + SizeIsNegative, + Oversized); 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 if (Oversized.getBoolValue()) + Diag(Loc, diag::err_array_too_large) + << Oversized.toString(10); else Diag(Loc, diag::err_typecheck_field_variable_size); InvalidDecl = true; |