aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/Expr.cpp111
-rw-r--r--lib/AST/StmtPrinter.cpp4
-rw-r--r--lib/Parse/ParseInit.cpp36
-rw-r--r--lib/Sema/Sema.cpp4
-rw-r--r--lib/Sema/Sema.h14
-rw-r--r--lib/Sema/SemaDecl.cpp3
-rw-r--r--lib/Sema/SemaInit.cpp391
7 files changed, 511 insertions, 52 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 03b49499ee..70b63fea1b 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1349,6 +1349,106 @@ void SizeOfAlignOfExpr::Destroy(ASTContext& C) {
}
//===----------------------------------------------------------------------===//
+// DesignatedInitExpr
+//===----------------------------------------------------------------------===//
+
+IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ if (Field.NameOrField & 0x01)
+ return reinterpret_cast<IdentifierInfo *>(Field.NameOrField&~0x01);
+ else
+ return getField()->getIdentifier();
+}
+
+DesignatedInitExpr *
+DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
+ unsigned NumDesignators,
+ Expr **IndexExprs, unsigned NumIndexExprs,
+ SourceLocation ColonOrEqualLoc,
+ bool UsesColonSyntax, Expr *Init) {
+ void *Mem = C.getAllocator().Allocate(sizeof(DesignatedInitExpr) +
+ sizeof(Designator) * NumDesignators +
+ sizeof(Stmt *) * (NumIndexExprs + 1),
+ 8);
+ DesignatedInitExpr *DIE
+ = new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators,
+ ColonOrEqualLoc, UsesColonSyntax,
+ NumIndexExprs + 1);
+
+ // Fill in the designators
+ unsigned ExpectedNumSubExprs = 0;
+ designators_iterator Desig = DIE->designators_begin();
+ for (unsigned Idx = 0; Idx < NumDesignators; ++Idx, ++Desig) {
+ new (static_cast<void*>(Desig)) Designator(Designators[Idx]);
+ if (Designators[Idx].isArrayDesignator())
+ ++ExpectedNumSubExprs;
+ else if (Designators[Idx].isArrayRangeDesignator())
+ ExpectedNumSubExprs += 2;
+ }
+ assert(ExpectedNumSubExprs == NumIndexExprs && "Wrong number of indices!");
+
+ // Fill in the subexpressions, including the initializer expression.
+ child_iterator Child = DIE->child_begin();
+ *Child++ = Init;
+ for (unsigned Idx = 0; Idx < NumIndexExprs; ++Idx, ++Child)
+ *Child = IndexExprs[Idx];
+
+ return DIE;
+}
+
+SourceRange DesignatedInitExpr::getSourceRange() const {
+ SourceLocation StartLoc;
+ Designator &First = *const_cast<DesignatedInitExpr*>(this)->designators_begin();
+ if (First.isFieldDesignator()) {
+ if (UsesColonSyntax)
+ StartLoc = SourceLocation::getFromRawEncoding(First.Field.FieldLoc);
+ else
+ StartLoc = SourceLocation::getFromRawEncoding(First.Field.DotLoc);
+ } else
+ StartLoc = SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc);
+ return SourceRange(StartLoc, getInit()->getSourceRange().getEnd());
+}
+
+DesignatedInitExpr::designators_iterator DesignatedInitExpr::designators_begin() {
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ return static_cast<Designator*>(static_cast<void*>(Ptr));
+}
+
+DesignatedInitExpr::designators_iterator DesignatedInitExpr::designators_end() {
+ return designators_begin() + NumDesignators;
+}
+
+Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
+ assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ Ptr += sizeof(Designator) * NumDesignators;
+ Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
+}
+
+Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
+ assert(D.Kind == Designator::ArrayRangeDesignator &&
+ "Requires array range designator");
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ Ptr += sizeof(Designator) * NumDesignators;
+ Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
+}
+
+Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
+ assert(D.Kind == Designator::ArrayRangeDesignator &&
+ "Requires array range designator");
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ Ptr += sizeof(Designator) * NumDesignators;
+ Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
+}
+
+//===----------------------------------------------------------------------===//
// ExprIterator.
//===----------------------------------------------------------------------===//
@@ -1533,6 +1633,17 @@ Stmt::child_iterator InitListExpr::child_end() {
return InitExprs.size() ? &InitExprs[0] + InitExprs.size() : 0;
}
+/// DesignatedInitExpr
+Stmt::child_iterator DesignatedInitExpr::child_begin() {
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ Ptr += sizeof(Designator) * NumDesignators;
+ return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+}
+Stmt::child_iterator DesignatedInitExpr::child_end() {
+ return child_iterator(&*child_begin() + NumSubExprs);
+}
+
// ObjCStringLiteral
Stmt::child_iterator ObjCStringLiteral::child_begin() {
return child_iterator();
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index a3a16aec5b..80de5b8ae4 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -877,6 +877,10 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
OS << " }";
}
+void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
+ // FIXME!
+}
+
void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
OS << "va_arg(";
PrintExpr(Node->getSubExpr());
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index ff73b0b9e1..b5d0ec05db 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -68,13 +68,16 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
if (Tok.is(tok::identifier)) {
Diag(Tok, diag::ext_gnu_old_style_field_designator);
- Designation &D = Designations.CreateDesignation(InitNum);
- D.AddDesignator(Designator::getField(Tok.getIdentifierInfo()));
- ConsumeToken(); // Eat the identifier.
+ const IdentifierInfo *FieldName = Tok.getIdentifierInfo();
+ SourceLocation NameLoc = ConsumeToken(); // Eat the identifier.
assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");
- ConsumeToken();
- return ParseInitializer();
+ SourceLocation ColonLoc = ConsumeToken();
+
+ Designation &D = Designations.CreateDesignation(InitNum);
+ D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
+ return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,
+ ParseInitializer());
}
// Desig - This is initialized when we see our first designator. We may have
@@ -86,7 +89,7 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
while (Tok.is(tok::period) || Tok.is(tok::l_square)) {
if (Tok.is(tok::period)) {
// designator: '.' identifier
- ConsumeToken();
+ SourceLocation DotLoc = ConsumeToken();
// Create designation if we haven't already.
if (Desig == 0)
@@ -97,7 +100,8 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
return ExprError();
}
- Desig->AddDesignator(Designator::getField(Tok.getIdentifierInfo()));
+ Desig->AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc,
+ Tok.getLocation()));
ConsumeToken(); // Eat the identifier.
continue;
}
@@ -179,11 +183,12 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
// If this is a normal array designator, remember it.
if (Tok.isNot(tok::ellipsis)) {
- Desig->AddDesignator(Designator::getArray(Idx.release()));
+ Desig->AddDesignator(Designator::getArray(Idx.release(),
+ StartLoc));
} else {
// Handle the gnu array range extension.
Diag(Tok, diag::ext_gnu_array_range);
- ConsumeToken();
+ SourceLocation EllipsisLoc = ConsumeToken();
OwningExprResult RHS(ParseConstantExpression());
if (RHS.isInvalid()) {
@@ -191,10 +196,12 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
return move(RHS);
}
Desig->AddDesignator(Designator::getArrayRange(Idx.release(),
- RHS.release()));
+ RHS.release(),
+ StartLoc, EllipsisLoc));
}
- MatchRHSPunctuation(tok::r_square, StartLoc);
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ Desig->getDesignator(Desig->getNumDesignators() - 1).setRBracketLoc(EndLoc);
}
// Okay, we're done with the designator sequence. We know that there must be
@@ -205,8 +212,9 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
// Handle a normal designator sequence end, which is an equal.
if (Tok.is(tok::equal)) {
- ConsumeToken();
- return ParseInitializer();
+ SourceLocation EqualLoc = ConsumeToken();
+ return Actions.ActOnDesignatedInitializer(*Desig, EqualLoc, false,
+ ParseInitializer());
}
// We read some number of designators and found something that isn't an = or
@@ -274,7 +282,7 @@ Parser::OwningExprResult Parser::ParseBraceInitializer() {
// If we had an erroneous initializer, and we had a potentially valid
// designator, make sure to remove the designator from
// InitExprDesignations, otherwise we'll end up with a designator with no
- // making initializer.
+ // matching initializer.
if (SubElt.isInvalid())
InitExprDesignations.EraseDesignation(InitExprs.size());
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 423b049124..a8cc404907 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -179,10 +179,10 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) {
}
void Sema::DeleteExpr(ExprTy *E) {
- static_cast<Expr*>(E)->Destroy(Context);
+ if (E) static_cast<Expr*>(E)->Destroy(Context);
}
void Sema::DeleteStmt(StmtTy *S) {
- static_cast<Stmt*>(S)->Destroy(Context);
+ if (S) static_cast<Stmt*>(S)->Destroy(Context);
}
/// ActOnEndOfTranslationUnit - This is called at the very end of the
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 49e3eb8b5c..b574dc360e 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -43,6 +43,7 @@ namespace clang {
class Stmt;
class Expr;
class InitListExpr;
+ class DesignatedInitExpr;
class CallExpr;
class DeclRefExpr;
class VarDecl;
@@ -1043,6 +1044,11 @@ public:
InitListDesignations &Designators,
SourceLocation RParenLoc);
+ virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig,
+ SourceLocation Loc,
+ bool UsedColonSyntax,
+ OwningExprResult Init);
+
virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
tok::TokenKind Kind,
ExprArg LHS, ExprArg RHS);
@@ -1833,15 +1839,17 @@ class InitListChecker {
void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
unsigned &Index);
void CheckSubElementType(InitListExpr *IList, QualType ElemType,
- unsigned &Index);
+ Expr *expr, unsigned &Index);
// FIXME: Does DeclType need to be a reference type?
void CheckScalarType(InitListExpr *IList, QualType &DeclType,
- unsigned &Index);
+ Expr *expr, unsigned &Index);
void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index);
void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType,
unsigned &Index);
void CheckArrayType(InitListExpr *IList, QualType &DeclType, unsigned &Index);
-
+ bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
+ QualType DeclType, FieldDecl *&DesignatedField,
+ llvm::APSInt &DesignatedIndex, unsigned &Index);
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
public:
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c1741da3b6..dbf1e7b416 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2184,6 +2184,9 @@ bool Sema::CheckArithmeticConstantExpression(const Expr* Init) {
}
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init))
+ Init = DIE->getInit();
+
Init = Init->IgnoreParens();
if (Init->isEvaluatable(Context))
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index f9c91ecaab..163dac94b9 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -12,13 +12,14 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "clang/Parse/Designator.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/Diagnostic.h"
#include <algorithm> // for std::count_if
#include <functional> // for std::mem_fun
-namespace clang {
+using namespace clang;
InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
hadError = false;
@@ -131,7 +132,7 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
QualType &DeclType,
unsigned &Index) {
if (DeclType->isScalarType()) {
- CheckScalarType(IList, DeclType, Index);
+ CheckScalarType(IList, DeclType, 0, Index);
} else if (DeclType->isVectorType()) {
CheckVectorType(IList, DeclType, Index);
} else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
@@ -156,8 +157,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
void InitListChecker::CheckSubElementType(InitListExpr *IList,
QualType ElemType,
+ Expr *expr,
unsigned &Index) {
- Expr* expr = IList->getInit(Index);
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
unsigned newIndex = 0;
CheckExplicitInitList(SubInitList, ElemType, newIndex);
@@ -167,7 +168,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
SemaRef->CheckStringLiteralInit(lit, ElemType);
Index++;
} else if (ElemType->isScalarType()) {
- CheckScalarType(IList, ElemType, Index);
+ CheckScalarType(IList, ElemType, expr, Index);
} else if (expr->getType()->getAsRecordType() &&
SemaRef->Context.typesAreCompatible(
expr->getType().getUnqualifiedType(),
@@ -180,10 +181,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
}
}
-void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
- unsigned &Index) {
+void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
+ Expr *expr, unsigned &Index) {
if (Index < IList->getNumInits()) {
- Expr* expr = IList->getInit(Index);
+ if (!expr)
+ expr = IList->getInit(Index);
if (isa<InitListExpr>(expr)) {
SemaRef->Diag(IList->getLocStart(),
diag::err_many_braces_around_scalar_init)
@@ -191,13 +193,26 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
hadError = true;
++Index;
return;
+ } else if (isa<DesignatedInitExpr>(expr)) {
+ SemaRef->Diag(expr->getSourceRange().getBegin(),
+ diag::err_designator_for_scalar_init)
+ << DeclType << expr->getSourceRange();
+ hadError = true;
+ ++Index;
+ return;
}
+
Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
if (SemaRef->CheckSingleInitializer(expr, DeclType, false))
hadError = true; // types weren't compatible.
- else if (savExpr != expr)
+ else if (savExpr != expr) {
// The type was promoted, update initializer list.
- IList->setInit(Index, expr);
+ if (DesignatedInitExpr *DIE
+ = dyn_cast<DesignatedInitExpr>(IList->getInit(Index)))
+ DIE->setInit(expr);
+ else
+ IList->setInit(Index, expr);
+ }
++Index;
} else {
SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
@@ -218,7 +233,7 @@ 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, Index);
+ CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
}
}
}
@@ -246,29 +261,63 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
return;
}
- int maxElements = numArrayElements(DeclType);
+ // FIXME: Will 32 bits always be enough? I hope so.
+ const unsigned ArraySizeBits = 32;
+ llvm::APSInt elementIndex(ArraySizeBits, 0);
+
+ // We might know the maximum number of elements in advance.
+ llvm::APSInt maxElements(ArraySizeBits, 0);
+ bool maxElementsKnown = false;
+ if (const ConstantArrayType *CAT =
+ SemaRef->Context.getAsConstantArrayType(DeclType)) {
+ maxElements = CAT->getSize();
+ maxElementsKnown = true;
+ }
+
QualType elementType = SemaRef->Context.getAsArrayType(DeclType)
->getElementType();
- int numElements = 0;
- for (int i = 0; i < maxElements; ++i, ++numElements) {
- // Don't attempt to go past the end of the init list
- if (Index >= IList->getNumInits())
+ while (Index < IList->getNumInits()) {
+ Expr *Init = IList->getInit(Index);
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
+ // C99 6.7.8p17:
+ // [...] In contrast, a designation causes the following
+ // initializer to begin initialization of the subobject
+ // described by the designator.
+ FieldDecl *DesignatedField = 0;
+ if (CheckDesignatedInitializer(IList, DIE, DeclType, DesignatedField,
+ elementIndex, Index))
+ hadError = true;
+
+ ++elementIndex;
+ continue;
+ }
+
+ // If we know the maximum number of elements, and we've already
+ // hit it, stop consuming elements in the initializer list.
+ if (maxElementsKnown && elementIndex == maxElements)
break;
- CheckSubElementType(IList, elementType, Index);
+
+ // Check this element.
+ CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
+ ++elementIndex;
+
+ // If the array is of incomplete type, keep track of the number of
+ // elements in the initializer.
+ if (!maxElementsKnown && elementIndex > maxElements)
+ maxElements = elementIndex;
}
if (DeclType->isIncompleteArrayType()) {
// If this is an incomplete array type, the actual type needs to
// be calculated here.
- if (numElements == 0) {
+ llvm::APInt Zero(ArraySizeBits, 0);
+ if (maxElements == Zero) {
// Sizing an array implicitly to zero is not allowed by ISO C,
// but is supported by GNU.
SemaRef->Diag(IList->getLocStart(),
diag::ext_typecheck_zero_array_size);
}
- llvm::APSInt ConstVal(32);
- ConstVal = numElements;
- DeclType = SemaRef->Context.getConstantArrayType(elementType, ConstVal,
+ DeclType = SemaRef->Context.getConstantArrayType(elementType, maxElements,
ArrayType::Normal, 0);
}
}
@@ -284,34 +333,310 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
hadError = true;
return;
}
- // If structDecl is a forward declaration, this loop won't do anything;
- // That's okay, because an error should get printed out elsewhere. It
- // might be worthwhile to skip over the rest of the initializer, though.
+ // If structDecl is a forward declaration, this loop won't do
+ // anything except look at designated initializers; That's okay,
+ // because an error should get printed out elsewhere. It might be
+ // worthwhile to skip over the rest of the initializer, though.
RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field) {
- // If we've hit the flexible array member at the end, we're done.
- if (Field->getType()->isIncompleteArrayType())
+ RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end();
+ while (Index < IList->getNumInits()) {
+ Expr *Init = IList->getInit(Index);
+
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
+ // C99 6.7.8p17:
+ // [...] In contrast, a designation causes the following
+ // initializer to begin initialization of the subobject
+ // described by the designator. Initialization then continues
+ // forward in order, beginning with the next subobject after
+ // that described by the designator.
+ FieldDecl *DesignatedField = 0;
+ llvm::APSInt LastElement;
+ if (CheckDesignatedInitializer(IList, DIE, DeclType, DesignatedField,
+ LastElement, Index)) {
+ hadError = true;
+ continue;
+ }
+
+ Field = RecordDecl::field_iterator(
+ DeclContext::decl_iterator(DesignatedField),
+ DeclType->getAsRecordType()->getDecl()->decls_end());
+ ++Field;
+ continue;
+ }
+
+ if (Field == FieldEnd) {
+ // We've run out of fields. We're done.
break;
+ }
- // Don't attempt to go past the end of the init list
- if (Index >= IList->getNumInits())
+ // If we've hit the flexible array member at the end, we're done.
+ if (Field->getType()->isIncompleteArrayType())
break;
if (!Field->getIdentifier()) {
// Don't initialize unnamed fields, e.g. "int : 20;"
+ ++Field;
continue;
}
- CheckSubElementType(IList, Field->getType(), Index);
- if (DeclType->isUnionType())
+ CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index);
+ if (DeclType->isUnionType()) // FIXME: designated initializers?
break;
+
+ ++Field;
}
// FIXME: Implement flexible array initialization GCC extension (it's a
// really messy extension to implement, unfortunately...the necessary
// information isn't actually even here!)
}
-} // end namespace clang
+/// @brief Check the well-formedness of a C99 designated initializer.
+///
+/// Determines whether the designated initializer @p DIE, which
+/// resides at the given @p Index within the initializer list @p
+/// 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).
+///
+/// @param IList The initializer list in which this designated
+/// initializer occurs.
+///
+/// @param DIE The designated initializer and its initialization
+/// expression.
+///
+/// @param DeclType The type of the "current object" (C99 6.7.8p17),
+/// into which the designation in @p DIE should refer.
+///
+/// @param DesignatedField If the first designator in @p DIE is a field,
+/// this will be set to the field declaration corresponding to the
+/// field named by the designator.
+///
+/// @param DesignatedIndex If the first designator in @p DIE is an
+/// array designator or GNU array-range designator, this will be set
+/// to the last index initialized by this designator.
+///
+/// @param Index Index into @p IList where the designated initializer
+/// @p DIE occurs.
+///
+/// @returns true if there was an error, false otherwise.
+bool InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
+ DesignatedInitExpr *DIE,
+ QualType DeclType,
+ FieldDecl *&DesignatedField,
+ llvm::APSInt &DesignatedIndex,
+ unsigned &Index) {
+ // DeclType is always the type of the "current object" (C99 6.7.8p17).
+
+ for (DesignatedInitExpr::designators_iterator D = DIE->designators_begin(),
+ DEnd = DIE->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ // C99 6.7.8p7:
+ //
+ // If a designator has the form
+ //
+ // . identifier
+ //
+ // then the current object (defined below) shall have
+ // structure or union type and the identifier shall be the
+ // name of a member of that type.
+ const RecordType *RT = DeclType->getAsRecordType();
+ if (!RT) {
+ SemaRef->Diag(DIE->getSourceRange().getBegin(),
+ diag::err_field_designator_non_aggr)
+ << SemaRef->getLangOptions().CPlusPlus << DeclType;
+ ++Index;
+ return true;
+ }
+
+ IdentifierInfo *FieldName = D->getFieldName();
+ DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+ FieldDecl *ThisField = 0;
+ if (Lookup.first == Lookup.second) {
+ // Lookup did not find anything with this name.
+ SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
+ << FieldName << DeclType;
+ } else if (isa<FieldDecl>(*Lookup.first)) {
+ // Name lookup found a field.
+ ThisField = 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);
+ }
+
+ if (!ThisField) {
+ ++Index;
+ return true;
+ }
+
+ // Update the designator with the field declaration.
+ D->setField(ThisField);
+
+ if (D == DIE->designators_begin())
+ DesignatedField = ThisField;
+
+ // The current object is now the type of this field.
+ DeclType = ThisField->getType();
+ } else {
+ // C99 6.7.8p6:
+ //
+ // If a designator has the form
+ //
+ // [ constant-expression ]
+ //
+ // then the current object (defined below) shall have array
+ // type and the expression shall be an integer constant
+ // expression. If the array is of unknown size, any
+ // nonnegative value is valid.
+ const ArrayType *AT = SemaRef->Context.getAsArrayType(DeclType);
+ if (!AT) {
+ SemaRef->Diag(D->getLBracketLoc(), diag::err_array_designator_non_array)
+ << DeclType;
+ ++Index;
+ return true;
+ }
+
+ Expr *IndexExpr = 0;
+ llvm::APSInt ThisIndex;
+ if (D->isArrayDesignator())
+ IndexExpr = DIE->getArrayIndex(*D);
+ else {
+ assert(D->isArrayRangeDesignator() && "Need array-range designator");
+ IndexExpr = DIE->getArrayRangeEnd(*D);
+ }
+
+ bool ConstExpr
+ = IndexExpr->isIntegerConstantExpr(ThisIndex, SemaRef->Context);
+ assert(ConstExpr && "Expression must be constant"); (void)ConstExpr;
+
+ if (isa<ConstantArrayType>(AT)) {
+ llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false);
+ if (ThisIndex >= MaxElements) {
+ SemaRef->Diag(IndexExpr->getSourceRange().getBegin(),
+ diag::err_array_designator_too_large)
+ << ThisIndex.toString(10) << MaxElements.toString(10);
+ ++Index;
+ return true;
+ }
+ }
+
+ if (D == DIE->designators_begin())
+ DesignatedIndex = ThisIndex;
+
+ // The current object is now the element type of this array.
+ DeclType = AT->getElementType();
+ }
+ }
+
+ // Check the actual initialization for the designated object type.
+ bool prevHadError = hadError;
+ CheckSubElementType(IList, DeclType, DIE->getInit(), Index);
+ return hadError && !prevHadError;
+}
+
+/// 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
+/// and produces a reasonable diagnostic if there is a
+/// failure. Returns true if there was an error, false otherwise. If
+/// everything went okay, Value will receive the value of the constant
+/// expression.
+static bool
+CheckArrayDesignatorExpr(Sema &Self, Expr *Index, llvm::APSInt &Value) {
+ SourceLocation Loc = Index->getSourceRange().getBegin();
+
+ // Make sure this is an integer constant expression.
+ if (!Index->isIntegerConstantExpr(Value, Self.Context, &Loc))
+ return Self.Diag(Loc, diag::err_array_designator_nonconstant)
+ << Index->getSourceRange();
+
+ // Make sure this constant expression is non-negative.
+ llvm::APSInt Zero(llvm::APSInt::getNullValue(Value.getBitWidth()), false);
+ if (Value < Zero)
+ return Self.Diag(Loc, diag::err_array_designator_negative)
+ << Value.toString(10) << Index->getSourceRange();
+
+ return false;
+}
+
+Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
+ SourceLocation Loc,
+ bool UsedColonSyntax,
+ OwningExprResult Init) {
+ typedef DesignatedInitExpr::Designator ASTDesignator;
+
+ bool Invalid = false;
+ llvm::SmallVector<ASTDesignator, 32> Designators;
+ llvm::SmallVector<Expr *, 32> InitExpressions;
+
+ // Build designators and check array designator expressions.
+ for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
+ const Designator &D = Desig.getDesignator(Idx);
+ switch (D.getKind()) {
+ case Designator::FieldDesignator:
+ Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
+ D.getFieldLoc()));
+ break;
+
+ case Designator::ArrayDesignator: {
+ Expr *Index = static_cast<Expr *>(D.getArrayIndex());
+ llvm::APSInt IndexValue;
+ if (CheckArrayDesignatorExpr(*this, Index, IndexValue))
+ Invalid = true;
+ else {
+ Designators.push_back(ASTDesignator(InitExpressions.size(),
+ D.getLBracketLoc(),
+ D.getRBracketLoc()));
+ InitExpressions.push_back(Index);
+ }
+ break;
+ }
+
+ case Designator::ArrayRangeDesignator: {
+ Expr *StartIndex = static_cast<Expr *>(D.getArrayRangeStart());
+ Expr *EndIndex = static_cast<Expr *>(D.getArrayRangeEnd());
+ llvm::APSInt StartValue;
+ llvm::APSInt EndValue;
+ if (CheckArrayDesignatorExpr(*this, StartIndex, StartValue) ||
+ CheckArrayDesignatorExpr(*this, EndIndex, EndValue))
+ Invalid = true;
+ else if (EndValue < StartValue) {
+ Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range)
+ << StartValue.toString(10) << EndValue.toString(10)
+ << StartIndex->getSourceRange() << EndIndex->getSourceRange();
+ Invalid = true;
+ } else {
+ Designators.push_back(ASTDesignator(InitExpressions.size(),
+ D.getLBracketLoc(),
+ D.getEllipsisLoc(),
+ D.getRBracketLoc()));
+ InitExpressions.push_back(StartIndex);
+ InitExpressions.push_back(EndIndex);
+ }
+ break;
+ }
+ }
+ }
+
+ if (Invalid || Init.isInvalid())
+ return ExprError();
+
+ // Clear out the expressions within the designation.
+ Desig.ClearExprs(*this);
+
+ DesignatedInitExpr *DIE
+ = DesignatedInitExpr::Create(Context, &Designators[0], Designators.size(),
+ &InitExpressions[0], InitExpressions.size(),
+ Loc, UsedColonSyntax,
+ static_cast<Expr *>(Init.release()));
+ return Owned(DIE);
+}