I figured I should get this out into the open, since my holding onto
it isn't very useful. It's essentially a patch replacing the whole of
initialization-list processing sema with a version written from
scratch.
I'm not really asking for review of this, because it has quite a few weaknesses.
1. It rewrites the whole thing from scratch, which is probably not the
best idea, even if it is only a few hundred lines.
2. I'm not really satisfied with the way this patch is written; it has
a lot of code duplication. Some of the logic is a bit tricky, and both
the duplicate loops both within the method and the inablility to reuse
the logic for codegen/analysis are serious issues.
3. It's not complete: I haven't gone over any of the logic required for vectors.
That said, the code does work, and I believe it implements C99 rules
correctly, so it might be useful source of ideas for Steve or whoever
else touches this code.
-Eli
Index: Sema/Sema.h
===================================================================
--- Sema/Sema.h (revision 46191)
+++ Sema/Sema.h (working copy)
@@ -739,7 +739,11 @@
bool CheckSingleInitializer(Expr *&simpleInit, QualType declType);
bool CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot,
QualType ElementType);
-
+
+bool CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType,
+ bool topLevel, unsigned& startIndex);
+bool IsStringLiteralInit(Expr* Expr, QualType& DeclType);
+
void CheckVariableInitList(QualType DeclType, InitListExpr *IList,
QualType ElementType,
int &nInitializers, bool &hadError);
Index: Sema/SemaDecl.cpp
===================================================================
--- Sema/SemaDecl.cpp (revision 46191)
+++ Sema/SemaDecl.cpp (working copy)
@@ -354,7 +354,208 @@
return dyn_cast_or_null<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
}
+#if 1
+bool Sema::IsStringLiteralInit(Expr* InitExpr, QualType& DeclType) {
+ if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType())
+ if (VAT->getSizeExpr())
+ return false;
+ if (StringLiteral *strLiteral = dyn_cast<StringLiteral>(InitExpr)) {
+ if (const ArrayType* arrType = DeclType->getAsArrayType()) {
+ // Note that we don't want to try and promote literal strings
+ // initializing arrays
+ QualType arrayElementType = arrType->getElementType();
+ const ConstantArrayType* strArrayType =
strLiteral->getType()->getAsConstantArrayType();
+ QualType strElementType = strArrayType->getElementType();
+ if (Context.typesAreCompatible(strElementType, arrayElementType)) {
+ if (const ConstantArrayType* CAT = arrType->getAsConstantArrayType()) {
+ if (strArrayType->getMaximumElements() > CAT->getMaximumElements() +
1) {
+ Diag(strLiteral->getSourceRange().getBegin(),
+ diag::warn_initializer_string_for_char_array_too_long,
+ strLiteral->getSourceRange());
+ }
+ strLiteral->setType(DeclType);
+ } else {
+ llvm::APSInt ConstVal(32);
+ ConstVal = strArrayType->getMaximumElements();
+ // Return a new array type (C99 6.7.8p22).
+ DeclType = Context.getConstantArrayType(arrType->getElementType(),
ConstVal,
+ ArrayType::Normal, 0);
+ // set type from "char *" to "constant array of char".
+ strLiteral->setType(DeclType);
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+// CheckInitializerListTypes - Checks the types of elements of an initializer
+// list. This function is recursive: it calls itself to initialize subelements
+// of aggregate types. Note that the topLevel parameter essentially refers to
+// whether this expression "owns" the initializer list passed in, or if this
+// initialization is taking elements out of a parent initializer. Each
+// call to this function adds zero or more to startIndex, reports any errors,
+// and returns true if it found any inconsistent types.
+bool Sema::CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType,
+ bool topLevel, unsigned& startIndex) {
+ bool hadError = false;
+
+ if (DeclType->isScalarType()) {
+ // The simplest case: initializing a single scalar
+ // FIXME: allow initializer lists for vectors
+ if (topLevel) {
+ Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init,
+ IList->getSourceRange());
+ }
+ if (startIndex < IList->getNumInits()) {
+ Expr* expr = IList->getInit(startIndex);
+ if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+ // FIXME: Should an error be reported here instead?
+ unsigned newIndex = 0;
+ CheckInitializerListTypes(SubInitList, DeclType, true, newIndex);
+ } else {
+ hadError |= CheckInitExpr(expr, IList, startIndex, DeclType);
+ }
+ ++startIndex;
+ }
+ // FIXME: Should an error be reported for empty initializer list + scalar?
+ } else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
+ if (DeclType->isStructureType() || DeclType->isUnionType()) {
+ if (startIndex < IList->getNumInits() &&
+ Context.typesAreCompatible(IList->getInit(startIndex)->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?
+ ++startIndex;
+ } else {
+ RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
+ // 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 = structDecl->getNumMembers() -
+ structDecl->hasFlexibleArrayMember();
+ for (int i = 0; i < numMembers; i++) {
+ // Don't attempt to go past the end of the init list
+ if (startIndex >= 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(startIndex);
+ if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+ unsigned newStart = 0;
+ hadError |= CheckInitializerListTypes(SubInitList, fieldType,
true, newStart);
+ ++startIndex;
+ } else {
+ hadError |= CheckInitializerListTypes(IList, fieldType, false,
startIndex);
+ }
+ if (DeclType->isUnionType())
+ break;
+ }
+ // FIXME: Implement flexible array initialization GCC extension (it's
a really
+ // messy extension to implement, unfortunately... the information
needed
+ // isn't actually even here!)
+ }
+ } else if (DeclType->isArrayType()) {
+ // Check for the special-case of initializing an array with a string.
+ if (startIndex < IList->getNumInits() &&
+ IsStringLiteralInit(IList->getInit(startIndex), DeclType)) {
+ ++startIndex;
+ return false;
+ }
+ int maxElements;
+ if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) {
+ // FIXME: use a proper constant
+ maxElements = 0x7FFFFFFF;
+ // 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).
+ if (const Expr *expr = VAT->getSizeExpr()) {
+ Diag(expr->getLocStart(), diag::err_variable_object_no_init,
+ expr->getSourceRange());
+ hadError = true;
+ }
+ } else {
+ const ConstantArrayType *CAT = DeclType->getAsConstantArrayType();
+ // FIXME: Is this really the right way to get this number?
+ maxElements = static_cast<int>(CAT->getSize().getZExtValue());
+ }
+ 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 (startIndex >= IList->getNumInits())
+ break;
+ Expr* expr = IList->getInit(startIndex);
+ if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+ unsigned newIndex = 0;
+ hadError |= CheckInitializerListTypes(SubInitList, elementType,
true, newIndex);
+ ++startIndex;
+ } else {
+ hadError |= CheckInitializerListTypes(IList, elementType, false,
startIndex);
+ }
+ }
+ if (DeclType->getAsVariableArrayType()) {
+ // 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.)
+ Diag(IList->getLocStart(),
+ diag::err_at_least_one_initializer_needed_to_size_array);
+ hadError = true;
+ } else {
+ llvm::APSInt ConstVal(32);
+ ConstVal = numElements;
+ DeclType = Context.getConstantArrayType(elementType, ConstVal,
+ ArrayType::Normal, 0);
+ }
+ }
+ } 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");
+ }
+
+ // If this init list is a base list, we set the type; an initializer doesn't
+ // fundamentally have a type, but this makes the ASTs a bit easier to read
+ if (topLevel)
+ IList->setType(DeclType);
+
+ if (topLevel && startIndex < IList->getNumInits()) {
+ // We have leftover initializers; warn
+ Diag(IList->getLocStart(), diag::warn_excess_initializers,
+ IList->getSourceRange());
+ }
+ return hadError;
+}
+
+bool Sema::CheckInitializerTypes(Expr *&Init, QualType& DeclType) {
+ InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
+ if (!InitList) {
+ // Check if this is a string literal initializing an array; we check
+ // here because CheckSingleInitializer expects a regular assignment.
+ if (IsStringLiteralInit(Init, DeclType))
+ return false;
+ return CheckSingleInitializer(Init, DeclType);
+ }
+
+ unsigned newIndex = 0;
+ return CheckInitializerListTypes(InitList, DeclType, true, newIndex);
+}
+#endif
bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) {
// Get the type before calling CheckSingleAssignmentConstraints(), since
// it can promote the expression.
@@ -375,7 +576,7 @@
IList->setInit(slot, expr);
return false;
}
-
+#if 0
void Sema::CheckVariableInitList(QualType DeclType, InitListExpr *IList,
QualType ElementType,
int &nInitializers, bool &hadError) {
@@ -596,7 +797,7 @@
// CompoundLiteralExpr...
return hadError;
}
-
+#endif
Sema::DeclTy *
Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
ScopedDecl *LastDeclarator = dyn_cast_or_null<ScopedDecl>((Decl *)lastDecl);
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev