aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
+ // Build a structured initializer list corresponding to this subobject.
+ InitListExpr *StructuredSubobjectInitList
+ = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList,
+ StructuredIndex,
+ ParentIList->getInit(Index)->getSourceRange());
+ unsigned StructuredSubobjectInitIndex = 0;
+
+ // Check the element types and build the structural subobject.
+ CheckListElementTypes(ParentIList, T, false, Index,
+ StructuredSubobjectInitList,
+ StructuredSubobjectInitIndex);
}
void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
- unsigned &Index) {
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
-
- CheckListElementTypes(IList, T, true, Index);
+ SyntacticToSemantic[IList] = StructuredList;
+ StructuredList->setSyntacticForm(IList);
+ CheckListElementTypes(IList, T, true, Index, StructuredList,
+ StructuredIndex);
IList->setType(T);
+ StructuredList->setType(T);
if (hadError)
return;
@@ -131,27 +184,31 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
void InitListChecker::CheckListElementTypes(InitListExpr *IList,
QualType &DeclType,
bool SubobjectIsDesignatorContext,
- unsigned &Index) {
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
if (DeclType->isScalarType()) {
- CheckScalarType(IList, DeclType, 0, Index);
+ CheckScalarType(IList, DeclType, 0, Index, StructuredList, StructuredIndex);
} else if (DeclType->isVectorType()) {
- CheckVectorType(IList, DeclType, Index);
+ CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
} else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
if (DeclType->isStructureType() || DeclType->isUnionType()) {
RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
- SubobjectIsDesignatorContext, Index);
+ SubobjectIsDesignatorContext, Index,
+ StructuredList, StructuredIndex);
} else if (DeclType->isArrayType()) {
llvm::APSInt Zero(
SemaRef->Context.getTypeSize(SemaRef->Context.getSizeType()),
false);
- CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index);
+ CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
+ StructuredList, StructuredIndex);
}
else
- assert(0 && "Aggregate that isn't a function or array?!");
+ assert(0 && "Aggregate that isn't a structure or array?!");
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
// This type is invalid, issue a diagnostic.
- Index++;
+ ++Index;
SemaRef->Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
<< DeclType;
hadError = true;
@@ -165,31 +222,46 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
void InitListChecker::CheckSubElementType(InitListExpr *IList,
QualType ElemType,
Expr *expr,
- unsigned &Index) {
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
unsigned newIndex = 0;
- CheckExplicitInitList(SubInitList, ElemType, newIndex);
- Index++;
+ unsigned newStructuredIndex = 0;
+ InitListExpr *newStructuredList
+ = getStructuredSubobjectInit(IList, Index, ElemType,
+ StructuredList, StructuredIndex,
+ SubInitList->getSourceRange());
+ CheckExplicitInitList(SubInitList, ElemType, newIndex,
+ newStructuredList, newStructuredIndex);
+ ++StructuredIndex;
+ ++Index;
} else if (StringLiteral *lit =
SemaRef->IsStringLiteralInit(expr, ElemType)) {
SemaRef->CheckStringLiteralInit(lit, ElemType);
- Index++;
+ UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
+ ++Index;
} else if (ElemType->isScalarType()) {
- CheckScalarType(IList, ElemType, expr, Index);
+ CheckScalarType(IList, ElemType, expr, Index, StructuredList,
+ StructuredIndex);
} else if (expr->getType()->getAsRecordType() &&
SemaRef->Context.typesAreCompatible(
expr->getType().getUnqualifiedType(),
ElemType.getUnqualifiedType())) {
- Index++;
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ ++Index;
// FIXME: Add checking
} else {
- CheckImplicitInitList(IList, ElemType, Index);
- Index++;
- }
+ CheckImplicitInitList(IList, ElemType, Index, StructuredList,
+ StructuredIndex);
+ ++StructuredIndex;
+ }
}
void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
- Expr *expr, unsigned &Index) {
+ Expr *expr, unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
if (Index < IList->getNumInits()) {
if (!expr)
expr = IList->getInit(Index);
@@ -199,6 +271,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
<< IList->getSourceRange();
hadError = true;
++Index;
+ ++StructuredIndex;
return;
} else if (isa<DesignatedInitExpr>(expr)) {
SemaRef->Diag(expr->getSourceRange().getBegin(),
@@ -206,6 +279,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
<< DeclType << expr->getSourceRange();
hadError = true;
++Index;
+ ++StructuredIndex;
return;
}
@@ -219,18 +293,27 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
DIE->setInit(expr);
else
IList->setInit(Index, expr);
+
}
+ if (hadError)
+ ++StructuredIndex;
+ else
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
} else {
SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
<< IList->getSourceRange();
hadError = true;
+ ++Index;
+ ++StructuredIndex;
return;
}
}
void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
- unsigned &Index) {
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
if (Index < IList->getNumInits()) {
const VectorType *VT = DeclType->getAsVectorType();
int maxElements = VT->getNumElements();
@@ -240,7 +323,8 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
break;
- CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
+ CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
+ StructuredList, StructuredIndex);
}
}
}
@@ -248,12 +332,21 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext,
- unsigned &Index) {
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
// 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);
+ // We place the string literal directly into the resulting
+ // initializer list. This is the only place where the structure
+ // of the structured initializer list doesn't match exactly,
+ // because doing so would involve allocating one character
+ // constant for each string.
+ UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
+ StructuredList->resizeInits(SemaRef->Context, StructuredIndex);
++Index;
return;
}
@@ -267,11 +360,14 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
diag::err_variable_object_no_init)
<< VAT->getSizeExpr()->getSourceRange();
hadError = true;
+ ++Index;
+ ++StructuredIndex;
return;
}
// We might know the maximum number of elements in advance.
- llvm::APSInt maxElements(elementIndex.getBitWidth(), elementIndex.isUnsigned());
+ llvm::APSInt maxElements(elementIndex.getBitWidth(),
+ elementIndex.isUnsigned());
bool maxElementsKnown = false;
if (const ConstantArrayType *CAT =
SemaRef->Context.getAsConstantArrayType(DeclType)) {
@@ -295,7 +391,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
// Handle this designated initializer. elementIndex will be
// updated to be the next array element we'll initialize.
if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(),
- DeclType, 0, &elementIndex, Index)) {
+ DeclType, 0, &elementIndex, Index,
+ StructuredList, StructuredIndex)) {
hadError = true;
continue;
}
@@ -320,7 +417,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
break;
// Check this element.
- CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
+ CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
+ StructuredList, StructuredIndex);
++elementIndex;
// If the array is of incomplete type, keep track of the number of
@@ -348,7 +446,9 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
QualType DeclType,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext,
- unsigned &Index) {
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
// If the record is invalid, some of it's members are invalid. To avoid
@@ -376,7 +476,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(),
- DeclType, &Field, 0, Index))
+ DeclType, &Field, 0, Index,
+ StructuredList, StructuredIndex))
hadError = true;
continue;
@@ -391,13 +492,14 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
if (Field->getType()->isIncompleteArrayType())
break;
- if (!Field->getIdentifier()) {
- // Don't initialize unnamed fields, e.g. "int : 20;"
+ if (!Field->getIdentifier() && Field->isBitField()) {
+ // Don't initialize unnamed bitfields, e.g. "int : 20;"
++Field;
continue;
}
- CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index);
+ CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index,
+ StructuredList, StructuredIndex);
if (DeclType->isUnionType()) // FIXME: designated initializers?
break;
@@ -416,8 +518,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
/// IList, is well-formed for a current object of type @p DeclType
/// (C99 6.7.8). The actual subobject that this designator refers to
/// within the current subobject is returned in either
-/// @p DesignatedField or @p DesignatedIndex (whichever is
-/// appropriate).
+/// @p NextField or @p NextElementIndex (whichever is appropriate).
///
/// @param IList The initializer list in which this designated
/// initializer occurs.
@@ -439,6 +540,10 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
/// @param Index Index into @p IList where the designated initializer
/// @p DIE occurs.
///
+/// @param StructuredList The initializer list expression that
+/// describes all of the subobject initializers in the order they'll
+/// actually be initialized.
+///
/// @returns true if there was an error, false otherwise.
bool
InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
@@ -447,16 +552,30 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
llvm::APSInt *NextElementIndex,
- unsigned &Index) {
- bool IsFirstDesignator = (D == DIE->designators_begin());
-
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
if (D == DIE->designators_end()) {
// Check the actual initialization for the designated object type.
bool prevHadError = hadError;
- CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index);
+ CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index,
+ StructuredList, StructuredIndex);
return hadError && !prevHadError;
}
+ bool IsFirstDesignator = (D == DIE->designators_begin());
+ assert((IsFirstDesignator || StructuredList) &&
+ "Need a non-designated initializer list to start from");
+
+ // Determine the structural initializer list that corresponds to the
+ // current subobject.
+ StructuredList = IsFirstDesignator? SyntacticToSemantic[IList]
+ : getStructuredSubobjectInit(IList, Index, CurrentObjectType, StructuredList,
+ StructuredIndex,
+ SourceRange(D->getStartLocation(),
+ DIE->getSourceRange().getEnd()));
+ assert(StructuredList && "Expected a structured initializer list");
+
if (D->isFieldDesignator()) {
// C99 6.7.8p7:
//
@@ -478,56 +597,95 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
return true;
}
+ // Note: we perform a linear search of the fields here, despite
+ // the fact that we have a faster lookup method, because we always
+ // need to compute the field's index.
IdentifierInfo *FieldName = D->getFieldName();
- DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
- FieldDecl *DesignatedField = 0;
- if (Lookup.first == Lookup.second) {
- // Lookup did not find anything with this name.
- SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
- << FieldName << CurrentObjectType;
- } else if (isa<FieldDecl>(*Lookup.first)) {
- // Name lookup found a field.
- DesignatedField = cast<FieldDecl>(*Lookup.first);
- // FIXME: Make sure this isn't a field in an anonymous
- // struct/union.
- } else {
- // Name lookup found something, but it wasn't a field.
- SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
- << FieldName;
- SemaRef->Diag((*Lookup.first)->getLocation(),
- diag::note_field_designator_found);
+ unsigned FieldIndex = 0;
+ RecordDecl::field_iterator Field = RT->getDecl()->field_begin(),
+ FieldEnd = RT->getDecl()->field_end();
+ for (; Field != FieldEnd; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (Field->getIdentifier() == FieldName)
+ break;
+
+ ++FieldIndex;
}
- if (!DesignatedField) {
+ if (Field == FieldEnd) {
+ // We did not find the field we're looking for. Produce a
+ // suitable diagnostic and return a failure.
+ DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+ if (Lookup.first == Lookup.second) {
+ // Name lookup didn't find anything.
+ SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
+ << FieldName << CurrentObjectType;
+ } else {
+ // Name lookup found something, but it wasn't a field.
+ SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
+ << FieldName;
+ SemaRef->Diag((*Lookup.first)->getLocation(),
+ diag::note_field_designator_found);
+ }
+
+ ++Index;
+ return true;
+ } else if (cast<RecordDecl>((*Field)->getDeclContext())
+ ->isAnonymousStructOrUnion()) {
+ SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_anon_class)
+ << FieldName
+ << (cast<RecordDecl>((*Field)->getDeclContext())->isUnion()? 2 :
+ (int)SemaRef->getLangOptions().CPlusPlus);
+ SemaRef->Diag((*Field)->getLocation(), diag::note_field_designator_found);
++Index;
return true;
}
-
+
+ // All of the fields of a union are located at the same place in
+ // the initializer list.
+ // FIXME: Need to tell CodeGen which type to initialize to. ImplicitCastExpr?
+ if (RT->getDecl()->isUnion() && FieldIndex != 0) {
+ SemaRef->Diag(D->getStartLocation(),
+ diag::warn_designator_into_union_broken_init)
+ << SourceRange(D->getStartLocation(), DIE->getSourceRange().getEnd());
+ FieldIndex = 0;
+ }
+
// Update the designator with the field declaration.
- D->setField(DesignatedField);
+ D->setField(*Field);
+ // Make sure that our non-designated initializer list has space
+ // for a subobject corresponding to this field.
+ if (FieldIndex >= StructuredList->getNumInits())
+ StructuredList->resizeInits(SemaRef->Context, FieldIndex + 1);
+
// Recurse to check later designated subobjects.
- QualType FieldType = DesignatedField->getType();
- if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index))
+ QualType FieldType = (*Field)->getType();
+ unsigned newStructuredIndex = FieldIndex;
+ if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index,
+ StructuredList, newStructuredIndex))
return true;
// Find the position of the next field to be initialized in this
// subobject.
- RecordDecl::field_iterator Field(DeclContext::decl_iterator(DesignatedField),
- RT->getDecl()->decls_end());
++Field;
+ ++FieldIndex;
// If this the first designator, our caller will continue checking
// the rest of this struct/class/union subobject.
if (IsFirstDesignator) {
if (NextField)
*NextField = Field;
+ StructuredIndex = FieldIndex;
return false;
}
// Check the remaining fields within this class/struct/union subobject.
bool prevHadError = hadError;
- CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index);
+ CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
+ StructuredList, FieldIndex);
return hadError && !prevHadError;
}
@@ -561,6 +719,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
else {
assert(D->isArrayRangeDesignator() && "Need array-range designator");
IndexExpr = DIE->getArrayRangeEnd(*D);
+ SemaRef->Diag(D->getEllipsisLoc(),
+ diag::warn_gnu_array_range_designator_unsupported)
+ << SourceRange(D->getLBracketLoc(), D->getRBracketLoc());
}
bool ConstExpr
@@ -581,28 +742,115 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
}
}
+ // Make sure that our non-designated initializer list has space
+ // for a subobject corresponding to this array element.
+ unsigned ElementIndex = DesignatedIndex.getZExtValue();
+ if (ElementIndex >= StructuredList->getNumInits())
+ StructuredList->resizeInits(SemaRef->Context, ElementIndex + 1);
+
// Recurse to check later designated subobjects.
QualType ElementType = AT->getElementType();
- if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index))
+ if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index,
+ StructuredList, ElementIndex))
return true;
// Move to the next index in the array that we'll be initializing.
++DesignatedIndex;
+ ElementIndex = DesignatedIndex.getZExtValue();
// If this the first designator, our caller will continue checking
// the rest of this array subobject.
if (IsFirstDesignator) {
if (NextElementIndex)
*NextElementIndex = DesignatedIndex;
+ StructuredIndex = ElementIndex;
return false;
}
// Check the remaining elements within this array subobject.
bool prevHadError = hadError;
- CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index);
+ CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index,
+ StructuredList, ElementIndex);
return hadError && !prevHadError;
}
+// Get the structured initializer list for a subobject of type
+// @p CurrentObjectType.
+InitListExpr *
+InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
+ QualType CurrentObjectType,
+ InitListExpr *StructuredList,
+ unsigned StructuredIndex,
+ SourceRange InitRange) {
+ Expr *ExistingInit = 0;
+ if (!StructuredList)
+ ExistingInit = SyntacticToSemantic[IList];
+ else if (StructuredIndex < StructuredList->getNumInits())
+ ExistingInit = StructuredList->getInit(StructuredIndex);
+
+ if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
+ return Result;
+
+ if (ExistingInit) {
+ // We are creating an initializer list that initializes the
+ // subobjects of the current object, but there was already an
+ // initialization that completely initialized the current
+ // subobject, e.g., by a compound literal:
+ //
+ // struct X { int a, b; };
+ // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
+ //
+ // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
+ // designated initializer re-initializes the whole
+ // subobject [0], overwriting previous initializers.
+ SemaRef->Diag(InitRange.getBegin(), diag::warn_subobject_initializer_overrides)
+ << InitRange;
+ SemaRef->Diag(ExistingInit->getSourceRange().getBegin(),
+ diag::note_previous_initializer)
+ << ExistingInit->hasSideEffects(SemaRef->Context)
+ << ExistingInit->getSourceRange();
+ }
+
+ InitListExpr *Result
+ = new (SemaRef->Context) InitListExpr(SourceLocation(), 0, 0,
+ SourceLocation());
+ Result->setType(CurrentObjectType);
+
+ // Link this new initializer list into the structured initializer
+ // lists.
+ if (StructuredList)
+ StructuredList->updateInit(StructuredIndex, Result);
+ else {
+ Result->setSyntacticForm(IList);
+ SyntacticToSemantic[IList] = Result;
+ }
+
+ return Result;
+}
+
+/// Update the initializer at index @p StructuredIndex within the
+/// structured initializer list to the value @p expr.
+void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ Expr *expr) {
+ // No structured initializer list to update
+ if (!StructuredList)
+ return;
+
+ if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
+ // This initializer overwrites a previous initializer. Warn.
+ SemaRef->Diag(expr->getSourceRange().getBegin(),
+ diag::warn_initializer_overrides)
+ << expr->getSourceRange();
+ SemaRef->Diag(PrevInit->getSourceRange().getBegin(),
+ diag::note_previous_initializer)
+ << (int)PrevInit->hasSideEffects(SemaRef->Context)
+ << PrevInit->getSourceRange();
+ }
+
+ ++StructuredIndex;
+}
+
/// Check that the given Index expression is a valid array designator
/// value. This is essentailly just a wrapper around
/// Expr::isIntegerConstantExpr that also checks for negative values
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
index 9d2a942410..3d2cf69127 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only -verify -pedantic %s
+// RUN: clang -fsyntax-only -pedantic -verify %s
extern int foof() = 1; // expected-error{{illegal initializer (only variables can be initialized)}}
@@ -101,6 +101,7 @@ void legal() {
{ 2, 3 },
{ 4, 5, 6 }
};
+ int q_sizecheck[(sizeof(q) / sizeof(short [3][2])) == 3? 1 : -1];
}
unsigned char asso_values[] = { 34 };
@@ -134,15 +135,19 @@ typedef int AryT[];
void testTypedef()
{
AryT a = { 1, 2 }, b = { 3, 4, 5 };
+ int a_sizecheck[(sizeof(a) / sizeof(int)) == 2? 1 : -1];
+ int b_sizecheck[(sizeof(b) / sizeof(int)) == 3? 1 : -1];
}
static char const xx[] = "test";
+int xx_sizecheck[(sizeof(xx) / sizeof(char)) == 5? 1 : -1];
static char const yy[5] = "test";
static char const zz[3] = "test"; // expected-warning{{initializer-string for char array is too long}}
void charArrays()
{
static char const test[] = "test";
+ int test_sizecheck[(sizeof(test) / sizeof(char)) == 5? 1 : -1];
static char const test2[] = { "weird stuff" };
static char const test3[] = { "test", "excess stuff" }; // expected-error{{excess elements in char array initializer}}
@@ -171,6 +176,7 @@ void variableArrayInit() {
float r1[10] = {{7}}; //expected-warning{{braces around scalar initializer}}
float r2[] = {{8}}; //expected-warning{{braces around scalar initializer}}
char r3[][5] = {1,2,3,4,5,6};
+int r3_sizecheck[(sizeof(r3) / sizeof(char[5])) == 2? 1 : -1];
char r3_2[sizeof r3 == 10 ? 1 : -1];
float r4[1][2] = {1,{2},3,4}; //expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in array initializer}}
char r5[][5] = {"aa", "bbb", "ccccc"};
@@ -195,7 +201,7 @@ int bar (void) {
return z.z;
}
struct s3 {void (*a)(void);} t5 = {autoStructTest};
-// GCC extension; flexible array init. Once this is implemented, the warning should be removed.
+// FIXME: GCC extension; flexible array init. Once this is implemented, the warning should be removed.
// Note that clang objc implementation depends on this extension.
struct {int a; int b[];} t6 = {1, {1, 2, 3}}; //expected-warning{{excess elements in array initializer}}
union {char a; int b;} t7[] = {1, 2, 3};
@@ -238,3 +244,21 @@ struct soft_segment_descriptor gdt_segs[] = {
static void sppp_ipv6cp_up();
const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-warning{{excess elements in array initializer}}
+
+struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a GNU extension in C}}
+typedef struct _Matrix Matrix;
+void test_matrix() {
+ const Matrix mat1 = {
+ { { 1.0f, 2.0f, 3.0f, 4.0f,
+ 5.0f, 6.0f, 7.0f, 8.0f,
+ 9.0f, 10.0f, 11.0f, 12.0f,
+ 13.0f, 14.0f, 15.0f, 16.0f } }
+ };
+
+ const Matrix mat2 = {
+ 1.0f, 2.0f, 3.0f, 4.0f,
+ 5.0f, 6.0f, 7.0f, 8.0f,
+ 9.0f, 10.0f, 11.0f, 12.0f,
+ 13.0f, 14.0f, 15.0f, 16.0f
+ };
+}
diff --git a/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c
index fd4873193c..c9a0aa7f05 100644
--- a/test/Sema/designated-initializers.c
+++ b/test/Sema/designated-initializers.c
@@ -18,7 +18,8 @@ int iarray2[10] = {
};
int iarray3[10] = {
- [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}
+ [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}\
+ // expected-warning{{GNU array-range designator extension is unsupported}}
};
struct point {
@@ -44,8 +45,8 @@ struct point array[10] = {
struct point array2[10] = {
[10].x = 2.0, // expected-error{{array designator index (10) exceeds array bounds (10)}}
- [4 ... 5].y = 2.0,
- [4 ... 6] = { .x = 3, .y = 4.0 }
+ [4 ... 5].y = 2.0, // expected-warning{{GNU array-range designator extension is unsupported}}
+ [4 ... 6] = { .x = 3, .y = 4.0 } // expected-warning{{GNU array-range designator extension is unsupported}}
};
struct point array3[10] = {
@@ -116,4 +117,25 @@ struct disklabel_ops disklabel64_ops = {
// PR clang/3378
int bitwidth[] = { [(long long int)1] = 5, [(short int)2] = 2 };
int a[]= { [sizeof(int)] = 0 };
-int a2[]= { [0 ... sizeof(int)] = 0 };
+int a2[]= { [0 ... sizeof(int)] = 0 }; // expected-warning{{GNU array-range designator extension is unsupported}}
+
+// Test warnings about initializers overriding previous initializers
+struct X {
+ int a, b, c;
+};
+
+int counter = 0;
+int get8() { ++counter; return 8; }
+
+void test() {
+ struct X xs[] = {
+ [0] = (struct X){1, 2}, // expected-note{{previous initialization is here}}
+ [0].c = 3, // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+ (struct X) {4, 5, 6}, // expected-note{{previous initialization is here}}
+ [1].b = get8(), // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+ [0].b = 8
+ };
+}
+
+// FIXME: we need to
+union { char c; long l; } u1 = { .l = 0xFFFF }; // expected-warning{{designated initialization of union member is broken}}
diff --git a/test/Sema/vector-init.c b/test/Sema/vector-init.c
index 1e2ba012c8..6913082228 100644
--- a/test/Sema/vector-init.c
+++ b/test/Sema/vector-init.c
@@ -1,5 +1,15 @@
-// RUN: clang %s -verify -fsyntax-only
+// RUN: clang %s -fsyntax-only -verify
typedef __attribute__(( ext_vector_type(4) )) float float4;
+//typedef float float4 __attribute__((vector_size(16)));
float4 foo = (float4){ 1.0, 2.0, 3.0, 4.0 };
+
+float4 array[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
+int array_sizecheck[(sizeof(array) / sizeof(float4)) == 3? 1 : -1];
+
+float4 array2[2] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
+ 9.0 }; // expected-warning {{excess elements in array initializer}}
+
+float4 array3[2] = { {1.0, 2.0, 3.0}, 5.0, 6.0, 7.0, 8.0,
+ 9.0 }; // expected-warning {{excess elements in array initializer}}