Initial implementation of semantic analysis and ASTs for C99

designated initializers. This implementation should cover all of the
constraints in C99 6.7.8, including long, complex designations and
computing the size of incomplete array types initialized with a
designated initializer. Please see the new test-case and holler if you
find cases where this doesn't work.

There are still some wrinkles with GNU's anonymous structs and
anonymous unions (it isn't clear how these should work; we'll just
follow GCC's lead) and with designated initializers for the members of a
union. I'll tackle those very soon.

CodeGen is still nonexistent, and there's some leftover code in the
parser's representation of designators that I'll also need to clean up.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62737 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-01-22 00:58:24 +00:00
Родитель db2868616b
Коммит 05c13a3411
13 изменённых файлов: 912 добавлений и 56 удалений

Просмотреть файл

@ -1706,6 +1706,224 @@ private:
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
//===----------------------------------------------------------------------===//

Просмотреть файл

@ -85,6 +85,7 @@ STMT(CStyleCastExpr , ExplicitCastExpr)
STMT(CompoundLiteralExpr , Expr)
STMT(ExtVectorElementExpr , Expr)
STMT(InitListExpr , Expr)
STMT(DesignatedInitExpr , Expr)
STMT(VAArgExpr , Expr)
// GNU Extensions.

Просмотреть файл

@ -698,6 +698,28 @@ DIAG(err_hex_escape_no_digits, ERROR,
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")

Просмотреть файл

@ -32,6 +32,7 @@ namespace clang {
class Scope;
class Action;
class Selector;
class Designation;
class InitListDesignations;
// Lex.
class Preprocessor;
@ -641,6 +642,26 @@ public:
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();

Просмотреть файл

@ -37,12 +37,18 @@ private:
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 {
@ -62,6 +68,16 @@ public:
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");
@ -77,28 +93,69 @@ public:
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.

Просмотреть файл

@ -1348,6 +1348,106 @@ void SizeOfAlignOfExpr::Destroy(ASTContext& C) {
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.
//===----------------------------------------------------------------------===//
@ -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();

Просмотреть файл

@ -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());

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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:

Просмотреть файл

@ -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))

Просмотреть файл

@ -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) {
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;
}
// If we've hit the flexible array member at the end, we're done.
if (Field->getType()->isIncompleteArrayType())
break;
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
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);
}

Просмотреть файл

@ -0,0 +1,78 @@
// 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 }
};