InitListExpr() : Expr(InitListExprClass, QualType()) {}
};
+/// @brief Represents a C99 designated initializer expression.
+///
+/// A designated initializer expression (C99 6.7.8) contains one or
+/// more designators (which can be field designators, array
+/// designators, or GNU array-range designators) followed by an
+/// expression that initializes the field or element(s) that the
+/// designators refer to. For example, given:
+///
+/// @code
+/// struct point {
+/// double x;
+/// double y;
+/// };
+/// struct point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 };
+/// @endcode
+///
+/// The InitListExpr contains three DesignatedInitExprs, the first of
+/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
+/// designators, one array designator for @c [2] followed by one field
+/// designator for @c .y. The initalization expression will be 1.0.
+class DesignatedInitExpr : public Expr {
+ /// The location of the '=' or ':' prior to the actual initializer
+ /// expression.
+ SourceLocation EqualOrColonLoc;
+
+ /// Whether this designated initializer used the GNU deprecated ':'
+ /// syntax rather than the C99 '=' syntax.
+ bool UsesColonSyntax : 1;
+
+ /// The number of designators in this initializer expression.
+ unsigned NumDesignators : 15;
+
+ /// The number of subexpressions of this initializer expression,
+ /// which contains both the initializer and any additional
+ /// expressions used by array and array-range designators.
+ unsigned NumSubExprs : 16;
+
+ DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+ SourceLocation EqualOrColonLoc, bool UsesColonSyntax,
+ unsigned NumSubExprs)
+ : Expr(DesignatedInitExprClass, Ty),
+ EqualOrColonLoc(EqualOrColonLoc), UsesColonSyntax(UsesColonSyntax),
+ NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) { }
+
+public:
+ /// A field designator, e.g., ".x".
+ struct FieldDesignator {
+ /// Refers to the field that is being initialized. The low bit
+ /// of this field determines whether this is actually a pointer
+ /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When
+ /// initially constructed, a field designator will store an
+ /// IdentifierInfo*. After semantic analysis has resolved that
+ /// name, the field designator will instead store a FieldDecl*.
+ uintptr_t NameOrField;
+
+ /// The location of the '.' in the designated initializer.
+ unsigned DotLoc;
+
+ /// The location of the field name in the designated initializer.
+ unsigned FieldLoc;
+ };
+
+ /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]".
+ struct ArrayOrRangeDesignator {
+ /// Location of the first index expression within the designated
+ /// initializer expression's list of subexpressions.
+ unsigned Index;
+ /// The location of the '[' starting the array range designator.
+ unsigned LBracketLoc;
+ /// The location of the ellipsis separating the start and end
+ /// indices. Only valid for GNU array-range designators.
+ unsigned EllipsisLoc;
+ /// The location of the ']' terminating the array range designator.
+ unsigned RBracketLoc;
+ };
+
+ /// @brief Represents a single C99 designator.
+ ///
+ /// @todo This class is infuriatingly similar to clang::Designator,
+ /// but minor differences (storing indices vs. storing pointers)
+ /// keep us from reusing it. Try harder, later, to rectify these
+ /// differences.
+ class Designator {
+ /// @brief The kind of designator this describes.
+ enum {
+ FieldDesignator,
+ ArrayDesignator,
+ ArrayRangeDesignator
+ } Kind;
+
+ union {
+ /// A field designator, e.g., ".x".
+ struct FieldDesignator Field;
+ /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]".
+ struct ArrayOrRangeDesignator ArrayOrRange;
+ };
+ friend class DesignatedInitExpr;
+
+ public:
+ /// @brief Initializes a field designator.
+ Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc,
+ SourceLocation FieldLoc)
+ : Kind(FieldDesignator) {
+ Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01;
+ Field.DotLoc = DotLoc.getRawEncoding();
+ Field.FieldLoc = FieldLoc.getRawEncoding();
+ }
+
+ /// @brief Initializes an array designator.
+ Designator(unsigned Index, SourceLocation LBracketLoc,
+ SourceLocation RBracketLoc)
+ : Kind(ArrayDesignator) {
+ ArrayOrRange.Index = Index;
+ ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding();
+ ArrayOrRange.EllipsisLoc = SourceLocation().getRawEncoding();
+ ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding();
+ }
+
+ /// @brief Initializes a GNU array-range designator.
+ Designator(unsigned Index, SourceLocation LBracketLoc,
+ SourceLocation EllipsisLoc, SourceLocation RBracketLoc)
+ : Kind(ArrayRangeDesignator) {
+ ArrayOrRange.Index = Index;
+ ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding();
+ ArrayOrRange.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding();
+ }
+
+ bool isFieldDesignator() const { return Kind == FieldDesignator; }
+ bool isArrayDesignator() const { return Kind == ArrayDesignator; }
+ bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; }
+
+ IdentifierInfo * getFieldName();
+
+ FieldDecl *getField() {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ if (Field.NameOrField & 0x01)
+ return 0;
+ else
+ return reinterpret_cast<FieldDecl *>(Field.NameOrField);
+ }
+
+ void setField(FieldDecl *FD) {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ Field.NameOrField = reinterpret_cast<uintptr_t>(FD);
+ }
+
+ SourceLocation getFieldLoc() const {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ return SourceLocation::getFromRawEncoding(Field.FieldLoc);
+ }
+
+ SourceLocation getLBracketLoc() const {
+ assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
+ "Only valid on an array or array-range designator");
+ return SourceLocation::getFromRawEncoding(ArrayOrRange.LBracketLoc);
+ }
+
+ SourceLocation getRBracketLoc() const {
+ assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
+ "Only valid on an array or array-range designator");
+ return SourceLocation::getFromRawEncoding(ArrayOrRange.RBracketLoc);
+ }
+
+ SourceLocation getEllipsisLoc() const {
+ assert(Kind == ArrayRangeDesignator &&
+ "Only valid on an array-range designator");
+ return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc);
+ }
+ };
+
+ static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
+ unsigned NumDesignators,
+ Expr **IndexExprs, unsigned NumIndexExprs,
+ SourceLocation EqualOrColonLoc,
+ bool UsesColonSyntax, Expr *Init);
+
+ /// @brief Returns the number of designators in this initializer.
+ unsigned size() const { return NumDesignators; }
+
+ // Iterator access to the designators.
+ typedef Designator* designators_iterator;
+ designators_iterator designators_begin();
+ designators_iterator designators_end();
+
+ Expr *getArrayIndex(const Designator& D);
+ Expr *getArrayRangeStart(const Designator& D);
+ Expr *getArrayRangeEnd(const Designator& D);
+
+ /// @brief Retrieve the location of the '=' that precedes the
+ /// initializer value itself, if present.
+ SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; }
+
+ /// @brief Determines whether this designated initializer used the
+ /// GNU 'fieldname:' syntax or the C99 '=' syntax.
+ bool usesColonSyntax() const { return UsesColonSyntax; }
+
+ /// @brief Retrieve the initializer value.
+ Expr *getInit() const {
+ return cast<Expr>(*const_cast<DesignatedInitExpr*>(this)->child_begin());
+ }
+
+ void setInit(Expr *init) {
+ *child_begin() = init;
+ }
+
+ virtual SourceRange getSourceRange() const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DesignatedInitExprClass;
+ }
+ static bool classof(const DesignatedInitExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
//===----------------------------------------------------------------------===//
// Clang Extensions
//===----------------------------------------------------------------------===//
STMT(CompoundLiteralExpr , Expr)
STMT(ExtVectorElementExpr , Expr)
STMT(InitListExpr , Expr)
+STMT(DesignatedInitExpr , Expr)
STMT(VAArgExpr , Expr)
// GNU Extensions.
DIAG(ext_predef_outside_function, WARNING,
"predefined identifier is only valid inside function")
+// C99 Designated Initializers
+DIAG(err_array_designator_nonconstant, ERROR,
+ "array designator value must be a constant expression")
+DIAG(err_array_designator_negative, ERROR,
+ "array designator value '%0' is negative")
+DIAG(err_array_designator_empty_range, ERROR,
+ "array designator range [%0, %1] is empty")
+DIAG(err_array_designator_non_array, ERROR,
+ "array designator cannot initialize non-array type %0")
+DIAG(err_array_designator_too_large, ERROR,
+ "array designator index (%0) exceeds array bounds (%1)")
+DIAG(err_field_designator_non_aggr, ERROR,
+ "field designator cannot initialize a %select{non-struct, non-union|non-class}0 type %1")
+DIAG(err_field_designator_unknown, ERROR,
+ "field designator %0 does not refer to any field in type %1")
+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_designator_for_scalar_init, ERROR,
+ "designator in initializer for scalar type %0")
+
// Declarations.
DIAG(err_typename_requires_specqual, ERROR,
"type name requires a specifier or qualifier")
class Scope;
class Action;
class Selector;
+ class Designation;
class InitListDesignations;
// Lex.
class Preprocessor;
SourceLocation RParenLoc) {
return ExprEmpty();
}
+ /// @brief Parsed a C99 designated initializer.
+ ///
+ /// @param Desig Contains the designation with one or more designators.
+ ///
+ /// @param Loc The location of the '=' or ':' prior to the
+ /// initialization expression.
+ ///
+ /// @param UsedColonSyntax If true, then this designated initializer
+ /// used the deprecated GNU syntax @c fieldname:foo rather than the
+ /// C99 syntax @c .fieldname=foo.
+ ///
+ /// @param Init The value that the entity (or entities) described by
+ /// the designation will be initialized with.
+ virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig,
+ SourceLocation Loc,
+ bool UsedColonSyntax,
+ OwningExprResult Init) {
+ return ExprEmpty();
+ }
+
virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg Op) {
return ExprEmpty();
struct FieldDesignatorInfo {
const IdentifierInfo *II;
+ unsigned DotLoc;
+ unsigned NameLoc;
};
struct ArrayDesignatorInfo {
Action::ExprTy *Index;
+ unsigned LBracketLoc;
+ mutable unsigned RBracketLoc;
};
struct ArrayRangeDesignatorInfo {
Action::ExprTy *Start, *End;
+ unsigned LBracketLoc, EllipsisLoc;
+ mutable unsigned RBracketLoc;
};
union {
assert(isFieldDesignator() && "Invalid accessor");
return FieldInfo.II;
}
+
+ SourceLocation getDotLoc() const {
+ assert(isFieldDesignator() && "Invalid accessor");
+ return SourceLocation::getFromRawEncoding(FieldInfo.DotLoc);
+ }
+
+ SourceLocation getFieldLoc() const {
+ assert(isFieldDesignator() && "Invalid accessor");
+ return SourceLocation::getFromRawEncoding(FieldInfo.NameLoc);
+ }
Action::ExprTy *getArrayIndex() const {
assert(isArrayDesignator() && "Invalid accessor");
return ArrayRangeInfo.End;
}
-
- static Designator getField(const IdentifierInfo *II) {
+ SourceLocation getLBracketLoc() const {
+ assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ "Invalid accessor");
+ if (isArrayDesignator())
+ return SourceLocation::getFromRawEncoding(ArrayInfo.LBracketLoc);
+ else
+ return SourceLocation::getFromRawEncoding(ArrayRangeInfo.LBracketLoc);
+ }
+
+ SourceLocation getRBracketLoc() const {
+ assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ "Invalid accessor");
+ if (isArrayDesignator())
+ return SourceLocation::getFromRawEncoding(ArrayInfo.RBracketLoc);
+ else
+ return SourceLocation::getFromRawEncoding(ArrayRangeInfo.RBracketLoc);
+ }
+
+ SourceLocation getEllipsisLoc() const {
+ assert(isArrayRangeDesignator() && "Invalid accessor");
+ return SourceLocation::getFromRawEncoding(ArrayRangeInfo.EllipsisLoc);
+ }
+
+ static Designator getField(const IdentifierInfo *II, SourceLocation DotLoc,
+ SourceLocation NameLoc) {
Designator D;
D.Kind = FieldDesignator;
D.FieldInfo.II = II;
+ D.FieldInfo.DotLoc = DotLoc.getRawEncoding();
+ D.FieldInfo.NameLoc = NameLoc.getRawEncoding();
return D;
}
- static Designator getArray(Action::ExprTy *Index) {
+ static Designator getArray(Action::ExprTy *Index, SourceLocation LBracketLoc) {
Designator D;
D.Kind = ArrayDesignator;
D.ArrayInfo.Index = Index;
+ D.ArrayInfo.LBracketLoc = LBracketLoc.getRawEncoding();
+ D.ArrayInfo.RBracketLoc = 0;
return D;
}
- static Designator getArrayRange(Action::ExprTy *Start, Action::ExprTy *End) {
+ static Designator getArrayRange(Action::ExprTy *Start, Action::ExprTy *End,
+ SourceLocation LBracketLoc,
+ SourceLocation EllipsisLoc) {
Designator D;
D.Kind = ArrayRangeDesignator;
D.ArrayRangeInfo.Start = Start;
D.ArrayRangeInfo.End = End;
+ D.ArrayRangeInfo.LBracketLoc = LBracketLoc.getRawEncoding();
+ D.ArrayRangeInfo.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ D.ArrayRangeInfo.RBracketLoc = 0;
return D;
}
+
+ void setRBracketLoc(SourceLocation RBracketLoc) const {
+ assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ "Invalid accessor");
+ if (isArrayDesignator())
+ ArrayInfo.RBracketLoc = RBracketLoc.getRawEncoding();
+ else
+ ArrayRangeInfo.RBracketLoc = RBracketLoc.getRawEncoding();
+ }
/// ClearExprs - Null out any expression references, which prevents them from
/// being 'delete'd later.
Expr::Destroy(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.
//===----------------------------------------------------------------------===//
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();
OS << " }";
}
+void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
+ // FIXME!
+}
+
void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
OS << "va_arg(";
PrintExpr(Node->getSubExpr());
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
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)
return ExprError();
}
- Desig->AddDesignator(Designator::getField(Tok.getIdentifierInfo()));
+ Desig->AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc,
+ Tok.getLocation()));
ConsumeToken(); // Eat the identifier.
continue;
}
// 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()) {
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
// 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
// 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());
}
}
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
class Stmt;
class Expr;
class InitListExpr;
+ class DesignatedInitExpr;
class CallExpr;
class DeclRefExpr;
class VarDecl;
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);
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:
}
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init))
+ Init = DIE->getInit();
+
Init = Init->IgnoreParens();
if (Init->isEvaluatable(Context))
//===----------------------------------------------------------------------===//
#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;
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()) {
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);
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(),
}
}
-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)
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)
// 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);
}
}
}
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);
}
}
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);
+}
--- /dev/null
+// RUN: clang -fsyntax-only -verify %s
+
+int iarray[10] = {
+ [0] = 1,
+ [1 ... 5] = 2,
+ [ 6 ... 6 ] = 3,
+ [ 8 ... 7 ] = 4, // expected-error{{array designator range [8, 7] is empty}}
+ [10] = 5,
+ [-1] = 6 // expected-error{{array designator value '-1' is negative}}
+};
+
+int iarray2[10] = {
+ [10] = 1, // expected-error{{array designator index (10) exceeds array bounds (10)}}
+ [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}
+};
+
+struct point {
+ double x;
+ double y;
+};
+
+struct point p1 = {
+ .y = 1.0,
+ x: 2.0,
+ .a = 4.0, // expected-error{{field designator 'a' does not refer to any field in type 'struct point'}}
+
+ [1] = 1.0 // expected-error{{array designator cannot initialize non-array type}}
+};
+
+struct point array[10] = {
+ [0].x = 1.0,
+ [1].y = 2.0,
+ [2].z = 3.0, // expected-error{{field designator 'z' does not refer to any field in type 'struct point'}}
+ [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 },
+ .x = 5 // expected-error{{field designator cannot initialize a non-struct, non-union type}}
+};
+
+struct rect {
+ struct point top_left;
+ struct point bottom_right;
+};
+
+struct rect window = { .top_left.x = 1.0 };
+
+struct rect windows[] = {
+ [2].top_left = { 1.0, 2.0 },
+ [4].bottom_right = { .y = 1.0 },
+ { { .y = 7.0, .x = 8.0 }, { .x = 5.0 } },
+ [3] = { .top_left = { 1.1, 2.2 }, .bottom_right = { .y = 1.1 } }
+};
+
+int windows_size[((sizeof(windows) / sizeof(struct rect)) == 6)? 1 : -1];
+
+struct rect windows_bad[3] = {
+ [2].top_left = { { .x = 1.1 } }, // expected-error{{designator in initializer for scalar type}}
+ [1].top_left = { .x = 1.1 }
+};
+
+struct gui {
+ struct rect windows[10];
+};
+
+struct gui gui[] = {
+ [5].windows[3].top_left.x = { 7.0 } // expected-warning{{braces around scalar initializer}}
+};
+
+struct translator {
+ struct wonky { int * ptr; } wonky ;
+ struct rect window;
+ struct point offset;
+} tran = {
+ .window = { .top_left = { 1.0, 2.0 } },
+ { .x = 5.0, .y = 6.0 },
+ .wonky = { 0 }
+};
+