aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-01-28 21:54:33 +0000
committerDouglas Gregor <dgregor@apple.com>2009-01-28 21:54:33 +0000
commit4c67834407ca6ab344dcf44fc599ad4938cfa96d (patch)
treed7d3838ffe094efc25517516290d26e484e2ca26
parentabf439731bc4f56df2df9e54d6c242e2c633f5ca (diff)
Code generation support for C99 designated initializers.
The approach I've taken in this patch is relatively straightforward, although the code itself is non-trivial. Essentially, as we process an initializer list we build up a fully-explicit representation of the initializer list, where each of the subobject initializations occurs in order. Designators serve to "fill in" subobject initializations in a non-linear way. The fully-explicit representation makes initializer lists (both with and without designators) easy to grok for codegen and later semantic analyses. We keep the syntactic form of the initializer list linked into the AST for those clients interested in exactly what the user wrote. Known limitations: - Designating a member of a union that isn't the first member may result in bogus initialization (we warn about this) - GNU array-range designators are not supported (we warn about this) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63242 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--Driver/RewriteObjC.cpp4
-rw-r--r--include/clang/AST/Decl.h3
-rw-r--r--include/clang/AST/Expr.h106
-rw-r--r--include/clang/AST/ExprCXX.h6
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def12
-rw-r--r--lib/AST/Expr.cpp28
-rw-r--r--lib/AST/StmtPrinter.cpp33
-rw-r--r--lib/CodeGen/CGExprAgg.cpp18
-rw-r--r--lib/CodeGen/CGExprConstant.cpp8
-rw-r--r--lib/CodeGen/CGExprScalar.cpp5
-rw-r--r--lib/Sema/Sema.h50
-rw-r--r--lib/Sema/SemaDecl.cpp9
-rw-r--r--lib/Sema/SemaExpr.cpp5
-rw-r--r--lib/Sema/SemaInit.cpp442
-rw-r--r--test/Sema/array-init.c28
-rw-r--r--test/Sema/designated-initializers.c30
-rw-r--r--test/Sema/vector-init.c12
17 files changed, 620 insertions, 179 deletions
diff --git a/Driver/RewriteObjC.cpp b/Driver/RewriteObjC.cpp
index 4524920f5a..e2ddafe8d1 100644
--- a/Driver/RewriteObjC.cpp
+++ b/Driver/RewriteObjC.cpp
@@ -2310,7 +2310,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE = new InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
- SourceLocation(), false);
+ SourceLocation());
SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE,
false);
// struct objc_super *
@@ -2391,7 +2391,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE = new InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
- SourceLocation(), false);
+ SourceLocation());
SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE, false);
}
MsgExprs.push_back(SuperRep);
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 988a7419a5..18d1c05467 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -678,6 +678,9 @@ public:
/// isBitfield - Determines whether this field is a bitfield.
bool isBitField() const { return BitWidth != NULL; }
+ /// @brief Determines whether this is an unnamed bitfield.
+ bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); }
+
/// isAnonymousStructOrUnion - Determines whether this field is a
/// representative for an anonymous struct or union. Such fields are
/// unnamed and are implicitly generated by the implementation to
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 5d768cd9db..861ac817cc 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -185,6 +185,10 @@ public:
/// initializer, which can be emitted at compile-time.
bool isConstantInitializer(ASTContext &Ctx) const;
+ /// @brief Determines whether this expression (or any of its
+ /// subexpressions) has side effects.
+ bool hasSideEffects(ASTContext &Ctx) const;
+
/// EvalResult is a struct with detailed info about an evaluated expression.
struct EvalResult {
/// Val - This is the scalar value the expression can be folded to.
@@ -1619,48 +1623,65 @@ public:
static VAArgExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
-/// InitListExpr - used for struct and array initializers, such as:
-/// struct foo x = { 1, { 2, 3 } };
+/// @brief Describes an C or C++ initializer list.
+///
+/// InitListExpr describes an initializer list, which can be used to
+/// initialize objects of different types, including
+/// struct/class/union types, arrays, and vectors. For example:
+///
+/// @code
+/// struct foo x = { 1, { 2, 3 } };
+/// @endcode
///
-/// Because C is somewhat loose with braces, the AST does not necessarily
-/// directly model the C source. Instead, the semantic analyzer aims to make
-/// the InitListExprs match up with the type of the decl being initialized. We
-/// have the following exceptions:
+/// Prior to semantic analysis, an initializer list will represent the
+/// initializer list as written by the user, but will have the
+/// placeholder type "void". This initializer list is called the
+/// syntactic form of the initializer, and may contain C99 designated
+/// initializers (represented as DesignatedInitExprs), initializations
+/// of subobject members without explicit braces, and so on. Clients
+/// interested in the original syntax of the initializer list should
+/// use the syntactic form of the initializer list.
///
-/// 1. Elements at the end of the list may be dropped from the initializer.
-/// These elements are defined to be initialized to zero. For example:
-/// int x[20] = { 1 };
-/// 2. Initializers may have excess initializers which are to be ignored by the
-/// compiler. For example:
-/// int x[1] = { 1, 2 };
-/// 3. Redundant InitListExprs may be present around scalar elements. These
-/// always have a single element whose type is the same as the InitListExpr.
-/// this can only happen for Type::isScalarType() types.
-/// int x = { 1 }; int y[2] = { {1}, {2} };
+/// After semantic analysis, the initializer list will represent the
+/// semantic form of the initializer, where the initializations of all
+/// subobjects are made explicit with nested InitListExpr nodes and
+/// C99 designators have been eliminated by placing the designated
+/// initializations into the subobject they initialize. Additionally,
+/// any "holes" in the initialization, where no initializer has been
+/// specified for a particular subobject, will be replaced with
+/// implicitly-generated CXXZeroInitValueExpr expressions that
+/// value-initialize the subobjects. Note, however, that the
+/// initializer lists may still have fewer initializers than there are
+/// elements to initialize within the object.
///
+/// Given the semantic form of the initializer list, one can retrieve
+/// the original syntactic form of that initializer list (if it
+/// exists) using getSyntacticForm(). Since many initializer lists
+/// have the same syntactic and semantic forms, getSyntacticForm() may
+/// return NULL, indicating that the current initializer list also
+/// serves as its syntactic form.
class InitListExpr : public Expr {
std::vector<Stmt *> InitExprs;
SourceLocation LBraceLoc, RBraceLoc;
- /// HadDesignators - Return true if there were any designators in this
- /// init list expr. FIXME: this should be replaced by storing the designators
- /// somehow and updating codegen.
- bool HadDesignators;
+ /// Contains the initializer list that describes the syntactic form
+ /// written in the source code.
+ InitListExpr *SyntacticForm;
+
public:
InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits,
- SourceLocation rbraceloc, bool HadDesignators);
+ SourceLocation rbraceloc);
unsigned getNumInits() const { return InitExprs.size(); }
- bool hadDesignators() const { return HadDesignators; }
const Expr* getInit(unsigned Init) const {
assert(Init < getNumInits() && "Initializer access out of range!");
- return cast<Expr>(InitExprs[Init]);
+ return cast_or_null<Expr>(InitExprs[Init]);
}
Expr* getInit(unsigned Init) {
assert(Init < getNumInits() && "Initializer access out of range!");
- return cast<Expr>(InitExprs[Init]);
+ return cast_or_null<Expr>(InitExprs[Init]);
}
void setInit(unsigned Init, Expr *expr) {
@@ -1668,13 +1689,22 @@ public:
InitExprs[Init] = expr;
}
- // Dynamic removal/addition (for constructing implicit InitExpr's).
- void removeInit(unsigned Init) {
- InitExprs.erase(InitExprs.begin()+Init);
- }
- void addInit(unsigned Init, Expr *expr) {
- InitExprs.insert(InitExprs.begin()+Init, expr);
- }
+ /// @brief Specify the number of initializers
+ ///
+ /// If there are more than @p NumInits initializers, the remaining
+ /// initializers will be destroyed. If there are fewer than @p
+ /// NumInits initializers, NULL expressions will be added for the
+ /// unknown initializers.
+ void resizeInits(ASTContext &Context, unsigned NumInits);
+
+ /// @brief Updates the initializer at index @p Init with the new
+ /// expression @p expr, and returns the old expression at that
+ /// location.
+ ///
+ /// When @p Init is out of range for this initializer list, the
+ /// initializer list will be extended with NULL expressions to
+ /// accomodate the new entry.
+ Expr *updateInit(unsigned Init, Expr *expr);
// Explicit InitListExpr's originate from source code (and have valid source
// locations). Implicit InitListExpr's are created by the semantic analyzer.
@@ -1682,6 +1712,13 @@ public:
return LBraceLoc.isValid() && RBraceLoc.isValid();
}
+ /// @brief Retrieve the initializer list that describes the
+ /// syntactic form of the initializer.
+ ///
+ ///
+ InitListExpr *getSyntacticForm() const { return SyntacticForm; }
+ void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; }
+
virtual SourceRange getSourceRange() const {
return SourceRange(LBraceLoc, RBraceLoc);
}
@@ -1885,6 +1922,13 @@ public:
"Only valid on an array-range designator");
return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc);
}
+
+ SourceLocation getStartLocation() const {
+ if (Kind == FieldDesignator)
+ return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc();
+ else
+ return getLBracketLoc();
+ }
};
static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 669e790b39..4f48eb3716 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -477,6 +477,12 @@ public:
SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
+ /// @brief Whether this initialization expression was
+ /// implicitly-generated.
+ bool isImplicit() const {
+ return TyBeginLoc.isInvalid() && RParenLoc.isInvalid();
+ }
+
virtual SourceRange getSourceRange() const {
return SourceRange(TyBeginLoc, RParenLoc);
}
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index 2959f6186b..222e39911b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -50,8 +50,20 @@ DIAG(err_field_designator_nonfield, ERROR,
"field designator %0 does not refer to a non-static data member")
DIAG(note_field_designator_found, NOTE,
"field designator refers here")
+DIAG(err_field_designator_anon_class, ERROR,
+ "field designator %0 refers to a member of an anonymous %select{struct|class|union}1")
DIAG(err_designator_for_scalar_init, ERROR,
"designator in initializer for scalar type %0")
+DIAG(warn_subobject_initializer_overrides, WARNING,
+ "subobject initialization overrides initialization of other fields within its enclosing subobject")
+DIAG(warn_initializer_overrides, WARNING,
+ "initializer overrides prior initialization of this subobject")
+DIAG(note_previous_initializer, NOTE,
+ "previous initialization %select{|with side effects }0is here%select{| (side effects may not occur at run time)}0")
+DIAG(warn_gnu_array_range_designator_unsupported, WARNING,
+ "GNU array-range designator extension is unsupported")
+DIAG(warn_designator_into_union_broken_init, WARNING,
+ "designated initialization of union member is broken")
// Declarations.
DIAG(ext_vla, EXTENSION,
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 8e43f99b67..ed73bfae27 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -221,13 +221,31 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
InitListExpr::InitListExpr(SourceLocation lbraceloc,
Expr **initExprs, unsigned numInits,
- SourceLocation rbraceloc, bool hadDesignators)
+ SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType()),
- LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), HadDesignators(hadDesignators) {
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) {
InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
}
+void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) {
+ for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); Idx < LastIdx; ++Idx)
+ delete InitExprs[Idx];
+ InitExprs.resize(NumInits, 0);
+}
+
+Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
+ if (Init >= InitExprs.size()) {
+ InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0);
+ InitExprs.back() = expr;
+ return 0;
+ }
+
+ Expr *Result = cast_or_null<Expr>(InitExprs[Init]);
+ InitExprs[Init] = expr;
+ return Result;
+}
+
/// getFunctionType - Return the underlying function type for this block.
///
const FunctionType *BlockExpr::getFunctionType() const {
@@ -740,6 +758,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
return isEvaluatable(Ctx);
}
+bool Expr::hasSideEffects(ASTContext &Ctx) const {
+ EvalResult Result;
+ Evaluate(Result, Ctx);
+ return Result.HasSideEffects;
+}
+
/// isIntegerConstantExpr - this recursive routine will test if an expression is
/// an integer constant expression. Note: With the introduction of VLA's in
/// C99 the result of the sizeof operator is no longer always a constant
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 80de5b8ae4..7a558ab8dd 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -872,13 +872,38 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
OS << "{ ";
for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
if (i) OS << ", ";
- PrintExpr(Node->getInit(i));
+ if (Node->getInit(i))
+ PrintExpr(Node->getInit(i));
+ else
+ OS << "0";
}
OS << " }";
}
void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
- // FIXME!
+ for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(),
+ DEnd = Node->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ if (D->getDotLoc().isInvalid())
+ OS << D->getFieldName()->getName() << ":";
+ else
+ OS << "." << D->getFieldName()->getName();
+ } else {
+ OS << "[";
+ if (D->isArrayDesignator()) {
+ PrintExpr(Node->getArrayIndex(*D));
+ } else {
+ PrintExpr(Node->getArrayRangeStart(*D));
+ OS << " ... ";
+ PrintExpr(Node->getArrayRangeEnd(*D));
+ }
+ OS << "]";
+ }
+ }
+
+ OS << " = ";
+ PrintExpr(Node->getInit());
}
void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
@@ -1187,7 +1212,9 @@ void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
//===----------------------------------------------------------------------===//
void Stmt::dumpPretty() const {
- printPretty(llvm::errs());
+ llvm::raw_ostream &OS = llvm::errs();
+ printPretty(OS);
+ OS.flush();
}
void Stmt::printPretty(llvm::raw_ostream &OS, PrinterHelper* Helper) const {
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 9181bf6654..2534a14cb6 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -71,7 +71,7 @@ public:
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
EmitAggLoadOfLValue(E);
}
-
+
// Operators.
// case Expr::UnaryOperatorClass:
// case Expr::CastExprClass:
@@ -303,11 +303,6 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
}
void AggExprEmitter::EmitNonConstInit(InitListExpr *E) {
- if (E->hadDesignators()) {
- CGF.ErrorUnsupported(E, "initializer list with designators");
- return;
- }
-
const llvm::PointerType *APType =
cast<llvm::PointerType>(DestPtr->getType());
const llvm::Type *DestType = APType->getElementType();
@@ -346,6 +341,8 @@ void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
// FIXME: Are initializers affected by volatile?
if (E->getType()->isComplexType()) {
CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
+ } else if (isa<CXXZeroInitValueExpr>(E)) {
+ EmitNullInitializationToLValue(LV, E->getType());
} else if (CGF.hasAggregateLLVMType(E->getType())) {
CGF.EmitAnyExpr(E, LV.getAddress(), false);
} else {
@@ -380,11 +377,6 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
}
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
- if (E->hadDesignators()) {
- CGF.ErrorUnsupported(E, "initializer list with designators");
- return;
- }
-
#if 0
// FIXME: Disabled while we figure out what to do about
// test/CodeGen/bitfield.c
@@ -426,7 +418,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
uint64_t NumArrayElements = AType->getNumElements();
QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
- ElementType =CGF.getContext().getAsArrayType(ElementType)->getElementType();
+ ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
unsigned CVRqualifier = ElementType.getCVRQualifiers();
@@ -479,7 +471,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
}
// Unions only initialize one field.
- // (things can get weird with designators, but they aren't
+ // (FIXME: things can get weird with designators, but they aren't
// supported yet.)
if (isUnion)
break;
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 32d126e590..3b6ebb4d56 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -242,6 +242,8 @@ public:
const llvm::Type *Ty = ConvertType(ILE->getType());
// Find the field decl we're initializing, if any
+ // FIXME: C99 designated initializers won't always initialize the
+ // first field
int FieldNo = 0; // Field no in RecordDecl
FieldDecl* curField = 0;
for (RecordDecl::field_iterator Field = RD->field_begin(),
@@ -304,12 +306,6 @@ public:
return llvm::Constant::getNullValue(RetTy);
}
- // FIXME: We don't codegen or sema designators yet.
- if (ILE->hadDesignators()) {
- CGM.ErrorUnsupported(ILE, "initializer list with designators");
- return llvm::UndefValue::get(ConvertType(ILE->getType()));
- }
-
if (ILE->getType()->isArrayType())
return EmitArrayInitialization(ILE);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 33c5a6124b..dd8b30041e 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -176,11 +176,6 @@ public:
if (!VType)
return Visit(E->getInit(0));
- if (E->hadDesignators()) {
- CGF.ErrorUnsupported(E, "initializer list with designators");
- return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
- }
-
unsigned NumVectorElements = VType->getNumElements();
const llvm::Type *ElementType = VType->getElementType();
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index d017e6f9c7..8cf10ff3e2 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -28,6 +28,7 @@
#include "llvm/ADT/OwningPtr.h"
#include <string>
#include <vector>
+#include <map>
namespace llvm {
class APSInt;
@@ -1835,38 +1836,67 @@ private:
class InitListChecker {
Sema *SemaRef;
bool hadError;
+ std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
+ InitListExpr *FullyStructuredList;
void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
- unsigned &Index);
+ unsigned &Index, InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex);
void CheckExplicitInitList(InitListExpr *IList, QualType &T,
- unsigned &Index);
-
+ unsigned &Index, InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex);
void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
bool SubobjectIsDesignatorContext,
- unsigned &Index);
+ unsigned &Index,
+ InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex);
void CheckSubElementType(InitListExpr *IList, QualType ElemType,
- Expr *expr, unsigned &Index);
+ Expr *expr, unsigned &Index,
+ InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex);
// FIXME: Does DeclType need to be a reference type?
void CheckScalarType(InitListExpr *IList, QualType &DeclType,
- Expr *expr, unsigned &Index);
- void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index);
+ Expr *expr, unsigned &Index,
+ InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex);
+ void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
+ InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex);
void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType,
RecordDecl::field_iterator Field,
- bool SubobjectIsDesignatorContext, unsigned &Index);
+ bool SubobjectIsDesignatorContext, unsigned &Index,
+ InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex);
void CheckArrayType(InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
- bool SubobjectIsDesignatorContext, unsigned &Index);
+ bool SubobjectIsDesignatorContext, unsigned &Index,
+ InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex);
bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
DesignatedInitExpr::designators_iterator D,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
llvm::APSInt *NextElementIndex,
- unsigned &Index);
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex);
+ InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
+ QualType CurrentObjectType,
+ InitListExpr *StructuredList,
+ unsigned StructuredIndex,
+ SourceRange InitRange);
+ void UpdateStructuredListElement(InitListExpr *StructuredInitList,
+ unsigned &StructuredInitIndex,
+ Expr *expr);
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
public:
InitListChecker(Sema *S, InitListExpr *IL, QualType &T);
bool HadError() { return hadError; }
+
+ // @brief Retrieves the fully-structured initializer list used for
+ // semantic analysis and code generation.
+ InitListExpr *getFullyStructuredList() const { return FullyStructuredList; }
};
/// BlockSemaInfo - When a block is being parsed, this contains information
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index cfbd288aae..79efc7df9c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1136,6 +1136,9 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
}
InitListChecker CheckInitList(this, InitList, DeclType);
+ if (!CheckInitList.HadError())
+ Init = CheckInitList.getFullyStructuredList();
+
return CheckInitList.HadError();
}
@@ -2209,6 +2212,12 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
for (unsigned i = 0; i < numInits; i++) {
// FIXME: Need to get the type of the declaration for C++,
// because it could be a reference?
+
+ // Implicitly-generated value initializations are okay.
+ if (isa<CXXZeroInitValueExpr>(Exp->getInit(i)) &&
+ cast<CXXZeroInitValueExpr>(Exp->getInit(i))->isImplicit())
+ continue;
+
if (CheckForConstantInitializer(Exp->getInit(i),
Exp->getInit(i)->getType()))
return true;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 770404d82a..064b8517f7 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1985,7 +1985,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
// CheckInitializer() - it requires knowledge of the object being intialized.
InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit,
- RBraceLoc, Designators.hasAnyDesignators());
+ RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
return Owned(E);
}
@@ -3988,8 +3988,7 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
// Otherwise, create a compound literal expression as the base, and
// iteratively process the offsetof designators.
InitListExpr *IList =
- new (Context) InitListExpr(SourceLocation(), 0, 0,
- SourceLocation(), false);
+ new (Context) InitListExpr(SourceLocation(), 0, 0, SourceLocation());
IList->setType(ArgTy);
Expr *Res =
new (Context) CompoundLiteralExpr(SourceLocation(), ArgTy, IList, false);
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 041e994bca..511a394d8f 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -15,19 +15,73 @@
#include "clang/Parse/Designator.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Basic/DiagnosticSema.h"
-#include <algorithm> // for std::count_if
-#include <functional> // for std::mem_fun
-
using namespace clang;
+/// Recursively replaces NULL values within the given initializer list
+/// with expressions that perform value-initialization of the
+/// appropriate type.
+static void fillInValueInitializations(ASTContext &Context, InitListExpr *ILE) {
+ assert((ILE->getType() != Context.VoidTy) && "Should not have void type");
+ if (const RecordType *RType = ILE->getType()->getAsRecordType()) {
+ unsigned Init = 0, NumInits = ILE->getNumInits();
+ for (RecordDecl::field_iterator Field = RType->getDecl()->field_begin(),
+ FieldEnd = RType->getDecl()->field_end();
+ Field != FieldEnd; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (Init >= NumInits)
+ break;
+
+ // FIXME: Check for fields with reference type in C++?
+ if (!ILE->getInit(Init))
+ ILE->setInit(Init,
+ new (Context) CXXZeroInitValueExpr(Field->getType(),
+ SourceLocation(),
+ SourceLocation()));
+ else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ fillInValueInitializations(Context, InnerILE);
+ ++Init;
+ }
+
+ return;
+ }
+
+ QualType ElementType;
+
+ if (const ArrayType *AType = Context.getAsArrayType(ILE->getType()))
+ ElementType = AType->getElementType();
+ else if (const VectorType *VType = ILE->getType()->getAsVectorType())
+ ElementType = VType->getElementType();
+ else
+ ElementType = ILE->getType();
+
+ for (unsigned Init = 0, NumInits = ILE->getNumInits(); Init != NumInits;
+ ++Init) {
+ if (!ILE->getInit(Init))
+ ILE->setInit(Init, new (Context) CXXZeroInitValueExpr(ElementType,
+ SourceLocation(),
+ SourceLocation()));
+ else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ fillInValueInitializations(Context, InnerILE);
+ }
+}
+
InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
hadError = false;
SemaRef = S;
unsigned newIndex = 0;
+ unsigned newStructuredIndex = 0;
+ FullyStructuredList
+ = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, SourceRange());
+ CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex);
- CheckExplicitInitList(IL, T, newIndex);
+ if (!hadError) {
+ fillInValueInitializations(SemaRef->Context, FullyStructuredList);
+ }
}
int InitListChecker::numArrayElements(QualType DeclType) {
@@ -42,17 +96,22 @@ int InitListChecker::numArrayElements(QualType DeclType) {
int InitListChecker::numStructUnionElements(QualType DeclType) {
RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
- const int InitializableMembers
- = std::count_if(structDecl->field_begin(), structDecl->field_end(),
- std::mem_fun(&FieldDecl::getDeclName));
+ int InitializableMembers = 0;
+ for (RecordDecl::field_iterator Field = structDecl->field_begin(),
+ FieldEnd = structDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ if ((*Field)->getIdentifier() || !(*Field)->isBitField())
+ ++InitializableMembers;
+ }
if (structDecl->isUnion())
return std::min(InitializableMembers, 1);
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
- QualType T, unsigned &Index) {
- llvm::SmallVector<Expr*, 4> InitExprs;
+ QualType T, unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
int maxElements = 0;
if (T->isArrayType())
@@ -64,45 +123,39 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
else
assert(0 && "CheckImplicitInitList(): Illegal type");
+ // FIXME: Perhaps we should move this warning elsewhere?
if (maxElements == 0) {
SemaRef->Diag(ParentIList->getInit(Index)->getLocStart(),
diag::err_implicit_empty_initializer);
+ ++Index;
hadError = true;
return;
}
- // Check the element types *before* we create the implicit init list;
- // otherwise, we might end up taking the wrong number of elements
- unsigned NewIndex = Index;
- CheckListElementTypes(ParentIList, T, false, NewIndex);
-
- 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(),
- ParentIList->hadDesignators());
- ILE->setType(T);
-
- // Modify the parent InitListExpr to point to the implicit InitListExpr.
- ParentIList->addInit(Index, ILE);