[cfe-commits] r50544 - in /cfe/trunk/lib/Sema: Sema.h SemaDecl.cpp SemaInit.cpp

Steve Naroff snaroff at apple.com
Thu May 1 15:18:59 PDT 2008


Author: snaroff
Date: Thu May  1 17:18:59 2008
New Revision: 50544

URL: http://llvm.org/viewvc/llvm-project?rev=50544&view=rev
Log:
Replace Sema::CheckInitializerListTypes() with a helper class (InitListChecker) that synthesizes implicit InitListExpr's when appropriate (see InitListExpr comments in Expr.h for more details). I also moved the code to SemaInit.cpp, to help reduce clutter in SemaDecl.cpp.

NOTE: This work is incomplete and still fails many tests (as a result, it isn't enabled yet). Nevertheless, I wanted to check it in so I can work on it from home.

Added:
    cfe/trunk/lib/Sema/SemaInit.cpp
Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=50544&r1=50543&r2=50544&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu May  1 17:18:59 2008
@@ -839,6 +839,7 @@
                                    IdentifierInfo &Comp, SourceLocation CmpLoc);
   
   /// type checking declaration initializers (C99 6.7.8)
+  friend class InitListChecker;
   bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType);
   bool CheckSingleInitializer(Expr *&simpleInit, QualType declType);
   bool CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot,
@@ -887,6 +888,32 @@
   void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
 };
 
+class InitListChecker {
+  Sema *SemaRef;
+  bool hadError;
+  
+  void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, 
+                             unsigned &Index);
+  void CheckExplicitInitList(InitListExpr *IList, QualType T,
+                             unsigned &Index);
+
+  void CheckElementTypes(InitListExpr *IList, QualType &DeclType, 
+                         unsigned &Index);
+  // FIXME: Does DeclType need to be a reference type?
+  void CheckScalarType(InitListExpr *IList, QualType &DeclType, 
+                       unsigned &Index);
+  void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index);
+  void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, 
+                             unsigned &Index);
+  void CheckArrayType(InitListExpr *IList, QualType &DeclType, unsigned &Index);
+  
+  int numArrayElements(QualType DeclType);
+  int numStructUnionElements(QualType DeclType);
+public:
+  InitListChecker(Sema *S, InitListExpr *IL, QualType &T);
+  bool HadError() { return hadError; }
+};
+
 
 }  // end namespace clang
 

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=50544&r1=50543&r2=50544&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu May  1 17:18:59 2008
@@ -730,8 +730,13 @@
 
     return CheckSingleInitializer(Init, DeclType);
   }
+#if 1
   unsigned newIndex = 0;
   return CheckInitializerListTypes(InitList, DeclType, true, newIndex);
+#else
+  InitListChecker CheckInitList(this, InitList, DeclType);
+  return CheckInitList.HadError();
+#endif
 }
 
 Sema::DeclTy *

Added: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=50544&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (added)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu May  1 17:18:59 2008
@@ -0,0 +1,292 @@
+//===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements semantic analysis for initializers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+
+namespace clang {
+
+InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
+  hadError = false;
+  SemaRef = S;
+  
+  if (IL) {
+    unsigned newIndex = 0;
+    CheckExplicitInitList(IL, T, newIndex);
+  } else {
+    // FIXME: Create an implicit InitListExpr with expressions from the
+    // parent checker.
+  }  
+}
+
+int InitListChecker::numArrayElements(QualType DeclType) {
+  int maxElements;
+  if (DeclType->isIncompleteArrayType()) {
+    // FIXME: use a proper constant
+    maxElements = 0x7FFFFFFF;
+  } else if (const VariableArrayType *VAT =
+             DeclType->getAsVariableArrayType()) {
+    // Check for VLAs; in standard C it would be possible to check this
+    // earlier, but I don't know where clang accepts VLAs (gcc accepts
+    // them in all sorts of strange places).
+    SemaRef->Diag(VAT->getSizeExpr()->getLocStart(),
+                  diag::err_variable_object_no_init,
+                  VAT->getSizeExpr()->getSourceRange());
+    hadError = true;
+    maxElements = 0x7FFFFFFF;
+  } else {
+    const ConstantArrayType *CAT = DeclType->getAsConstantArrayType();
+    maxElements = static_cast<int>(CAT->getSize().getZExtValue());
+  }
+  return maxElements;
+}
+
+int InitListChecker::numStructUnionElements(QualType DeclType) {
+  RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
+  return structDecl->getNumMembers() - structDecl->hasFlexibleArrayMember();
+}
+
+void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, 
+                                            QualType T, unsigned &Index) {
+  llvm::SmallVector<Expr*, 4> InitExprs;
+  int maxElements = 0;
+  
+  if (T->isArrayType())
+    maxElements = numArrayElements(T);
+  else if (T->isStructureType() || T->isUnionType())
+    maxElements = numStructUnionElements(T);
+  else
+    assert(0 && "CheckImplicitInitList(): Illegal type");
+  
+  for (int i = 0; i < maxElements; ++i) {
+    // Don't attempt to go past the end of the init list
+    if (Index >= ParentIList->getNumInits())
+      break;
+    Expr* expr = ParentIList->getInit(Index);
+    
+    // Add the expr to the new implicit init list and remove if from the old.
+    InitExprs.push_back(expr);
+    ParentIList->removeInit(Index);
+  }
+  // Synthesize an "implicit" InitListExpr (marked by the invalid source locs).
+  InitListExpr *ILE = new InitListExpr(SourceLocation(), 
+                                       &InitExprs[0], InitExprs.size(), 
+                                       SourceLocation());
+  ILE->setType(T);
+  
+  // Modify the parent InitListExpr to point to the implicit InitListExpr.
+  ParentIList->addInit(Index, ILE);
+  
+  // Now we can check the types.
+  CheckElementTypes(ParentIList, T, Index);
+}
+
+void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType T,
+                                            unsigned &Index) {
+  //assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
+  if (IList->isExplicit()) {
+    IList->setType(T);
+    
+    if (T->isScalarType())
+      SemaRef->Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init, 
+                    IList->getSourceRange());
+  }
+  CheckElementTypes(IList, T, Index);
+  if (Index < IList->getNumInits()) {
+    // We have leftover initializers; warn
+    SemaRef->Diag(IList->getInit(Index)->getLocStart(), 
+                  diag::warn_excess_initializers, 
+                  IList->getInit(Index)->getSourceRange());
+  }
+}
+
+void InitListChecker::CheckElementTypes(InitListExpr *IList, QualType &DeclType, 
+                                        unsigned &Index) {
+  if (DeclType->isScalarType())
+    CheckScalarType(IList, DeclType, Index);
+  else if (DeclType->isVectorType())
+    CheckVectorType(IList, DeclType, Index);
+  else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
+    if (DeclType->isStructureType() || DeclType->isUnionType())
+      CheckStructUnionTypes(IList, DeclType, Index);
+    else if (DeclType->isArrayType()) 
+      CheckArrayType(IList, DeclType, Index);
+    else
+      assert(0 && "Aggregate that isn't a function or array?!");
+  } else {
+    // In C, all types are either scalars or aggregates, but
+    // additional handling is needed here for C++ (and possibly others?). 
+    assert(0 && "Unsupported initializer type");
+  }
+}
+
+void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType, 
+                                      unsigned &Index) {
+  if (Index < IList->getNumInits()) {
+    Expr* expr = IList->getInit(Index);
+    if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+        unsigned newIndex = 0;
+        CheckExplicitInitList(SubInitList, DeclType, newIndex);
+    } else {
+      Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
+      if (SemaRef->CheckSingleInitializer(expr, DeclType))
+        hadError |= true; // types weren't compatible.
+      else if (savExpr != expr)
+        // The type was promoted, update initializer list.
+        IList->setInit(Index, expr);
+    }
+    ++Index;
+  }
+  // FIXME: Should an error be reported for empty initializer list + scalar?
+}
+
+void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, 
+                                      unsigned &Index) {
+  if (Index < IList->getNumInits()) {
+    const VectorType *VT = DeclType->getAsVectorType();
+    int maxElements = VT->getNumElements();
+    QualType elementType = VT->getElementType();
+    
+    for (int i = 0; i < maxElements; ++i) {
+      // Don't attempt to go past the end of the init list
+      if (Index >= IList->getNumInits())
+        break;
+      Expr* expr = IList->getInit(Index);
+      if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+        unsigned newIndex = 0;
+        CheckExplicitInitList(SubInitList, elementType, newIndex);
+        newIndex++;
+      } else
+        CheckImplicitInitList(IList, elementType, Index);
+    }
+  }
+}
+
+void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, 
+                                     unsigned &Index) {
+  // Check for the special-case of initializing an array with a string.
+  if (Index < IList->getNumInits()) {
+    if (StringLiteral *lit = 
+        SemaRef->IsStringLiteralInit(IList->getInit(Index), DeclType)) {
+      SemaRef->CheckStringLiteralInit(lit, DeclType);
+      ++Index;
+      if (IList->isExplicit() && Index < IList->getNumInits()) {
+        // We have leftover initializers; warn
+        SemaRef->Diag(IList->getInit(Index)->getLocStart(), 
+                      diag::err_excess_initializers_in_char_array_initializer, 
+                      IList->getInit(Index)->getSourceRange());
+      }
+      return;
+    }
+  }
+  int maxElements = numArrayElements(DeclType);
+  QualType elementType = DeclType->getAsArrayType()->getElementType();
+  int numElements = 0;
+  for (int i = 0; i < maxElements; ++i, ++numElements) {
+    // Don't attempt to go past the end of the init list
+    if (Index >= IList->getNumInits())
+      break;
+    Expr* expr = IList->getInit(Index);
+    
+    // Now, check the expression against the element type.
+    if (elementType->isScalarType())
+      CheckScalarType(IList, elementType, Index);
+    else if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+      unsigned newIndex = 0;
+      CheckExplicitInitList(SubInitList, elementType, newIndex);
+      Index++;
+#if 0
+    } else if (DeclType->isIncompleteArrayType()) {
+      // FIXME: Figure out how to call CheckImplicit InitList.
+      CheckElementTypes(IList, elementType, Index);
+#endif
+    } else {
+      CheckImplicitInitList(IList, elementType, Index);
+    }
+  }
+  if (DeclType->isIncompleteArrayType()) {
+    // If this is an incomplete array type, the actual type needs to
+    // be calculated here
+    if (numElements == 0) {
+      // Sizing an array implicitly to zero is not allowed
+      // (It could in theory be allowed, but it doesn't really matter.)
+      SemaRef->Diag(IList->getLocStart(),
+                    diag::err_at_least_one_initializer_needed_to_size_array);
+      hadError = true;
+    } else {
+      llvm::APSInt ConstVal(32);
+      ConstVal = numElements;
+      DeclType = SemaRef->Context.getConstantArrayType(elementType, ConstVal, 
+                                                       ArrayType::Normal, 0);
+    }
+  }
+}
+
+void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, 
+                                            QualType DeclType, 
+                                            unsigned &Index) {
+  if (Index < IList->getNumInits() && !IList->isExplicit() &&
+      SemaRef->Context.typesAreCompatible(
+        IList->getInit(Index)->getType(), DeclType)) {
+    // We found a compatible struct; per the standard, this initializes the
+    // struct.  (The C standard technically says that this only applies for
+    // initializers for declarations with automatic scope; however, this
+    // construct is unambiguous anyway because a struct cannot contain
+    // a type compatible with itself. We'll output an error when we check
+    // if the initializer is constant.)
+    // FIXME: Is a call to CheckSingleInitializer required here?
+    ++Index;
+  } else {
+    RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
+    
+    // If the record is invalid, some of it's members are invalid. To avoid
+    // confusion, we forgo checking the intializer for the entire record.
+    if (structDecl->isInvalidDecl()) {
+      hadError = true;
+      return;
+    }    
+    // If structDecl is a forward declaration, this loop won't do anything;
+    // That's okay, because an error should get printed out elsewhere. It
+    // might be worthwhile to skip over the rest of the initializer, though.
+    int numMembers = numStructUnionElements(DeclType);
+    for (int i = 0; i < numMembers; i++) {
+      // Don't attempt to go past the end of the init list
+      if (Index >= IList->getNumInits())
+        break;
+      FieldDecl * curField = structDecl->getMember(i);
+      if (!curField->getIdentifier()) {
+        // Don't initialize unnamed fields, e.g. "int : 20;"
+        continue;
+      }
+      QualType fieldType = curField->getType();
+      Expr* expr = IList->getInit(Index);
+      if (fieldType->isScalarType())
+        CheckScalarType(IList, fieldType, Index);
+      else if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+        unsigned newIndex = 0;
+        CheckExplicitInitList(SubInitList, fieldType, newIndex);
+        Index++;
+      } else
+        CheckImplicitInitList(IList, fieldType, Index);
+      if (DeclType->isUnionType())
+        break;
+    }
+    // FIXME: Implement flexible array initialization GCC extension (it's a 
+    // really messy extension to implement, unfortunately...the necessary
+    // information isn't actually even here!)
+  }
+}
+} // end namespace clang
+





More information about the cfe-commits mailing list