/// 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.
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) {
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.
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);
}
"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,
#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) {
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())
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;
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;
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);
<< IList->getSourceRange();
hadError = true;
++Index;
+ ++StructuredIndex;
return;
} else if (isa<DesignatedInitExpr>(expr)) {
SemaRef->Diag(expr->getSourceRange().getBegin(),
<< DeclType << expr->getSourceRange();
hadError = true;
++Index;
+ ++StructuredIndex;
return;
}
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();
// 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);
}
}
}
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;
}
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)) {
// 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;
}
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
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
// 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;
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;
/// 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.
/// @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,
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:
//
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;
}
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
}
}
+ // 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