]> granicus.if.org Git - clang/commitdiff
Re-fix r65140 correctly.
authorEli Friedman <eli.friedman@gmail.com>
Sat, 21 Feb 2009 00:44:51 +0000 (00:44 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Sat, 21 Feb 2009 00:44:51 +0000 (00:44 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65208 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDecl.cpp
lib/Sema/SemaType.cpp

index dfa1e03177993aed1aec11d02c694fb4841a21ca..faaa5290962a58863b0a27a34168ae49f22f9bb0 100644 (file)
@@ -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) {
index 8727fbcd8cc5ff3d811f66510b05d55719fa0b93..252cd2d533cee1c63a89d120ae322565837cf30f 100644 (file)
@@ -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();
           }
         }