Code generation support for C99 designated initializers.

The approach I've taken in this patch is relatively straightforward,
although the code itself is non-trivial. Essentially, as we process
an initializer list we build up a fully-explicit representation of the
initializer list, where each of the subobject initializations occurs
in order. Designators serve to "fill in" subobject initializations in
a non-linear way. The fully-explicit representation makes initializer
lists (both with and without designators) easy to grok for codegen and
later semantic analyses. We keep the syntactic form of the initializer
list linked into the AST for those clients interested in exactly what
the user wrote.

Known limitations:
  - Designating a member of a union that isn't the first member may
    result in bogus initialization (we warn about this)
  - GNU array-range designators are not supported (we warn about this)



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63242 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-01-28 21:54:33 +00:00
Родитель abf439731b
Коммит 4c67834407
17 изменённых файлов: 619 добавлений и 178 удалений

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

@ -2310,7 +2310,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE = new InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation(), false);
SourceLocation());
SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE,
false);
// struct objc_super *
@ -2391,7 +2391,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE = new InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation(), false);
SourceLocation());
SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE, false);
}
MsgExprs.push_back(SuperRep);

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

@ -678,6 +678,9 @@ public:
/// isBitfield - Determines whether this field is a bitfield.
bool isBitField() const { return BitWidth != NULL; }
/// @brief Determines whether this is an unnamed bitfield.
bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); }
/// isAnonymousStructOrUnion - Determines whether this field is a
/// representative for an anonymous struct or union. Such fields are
/// unnamed and are implicitly generated by the implementation to

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

@ -185,6 +185,10 @@ public:
/// initializer, which can be emitted at compile-time.
bool isConstantInitializer(ASTContext &Ctx) const;
/// @brief Determines whether this expression (or any of its
/// subexpressions) has side effects.
bool hasSideEffects(ASTContext &Ctx) const;
/// EvalResult is a struct with detailed info about an evaluated expression.
struct EvalResult {
/// Val - This is the scalar value the expression can be folded to.
@ -1619,48 +1623,65 @@ public:
static VAArgExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
/// InitListExpr - used for struct and array initializers, such as:
/// struct foo x = { 1, { 2, 3 } };
/// @brief Describes an C or C++ initializer list.
///
/// Because C is somewhat loose with braces, the AST does not necessarily
/// directly model the C source. Instead, the semantic analyzer aims to make
/// the InitListExprs match up with the type of the decl being initialized. We
/// have the following exceptions:
/// InitListExpr describes an initializer list, which can be used to
/// initialize objects of different types, including
/// struct/class/union types, arrays, and vectors. For example:
///
/// 1. Elements at the end of the list may be dropped from the initializer.
/// These elements are defined to be initialized to zero. For example:
/// int x[20] = { 1 };
/// 2. Initializers may have excess initializers which are to be ignored by the
/// compiler. For example:
/// int x[1] = { 1, 2 };
/// 3. Redundant InitListExprs may be present around scalar elements. These
/// always have a single element whose type is the same as the InitListExpr.
/// this can only happen for Type::isScalarType() types.
/// int x = { 1 }; int y[2] = { {1}, {2} };
/// @code
/// struct foo x = { 1, { 2, 3 } };
/// @endcode
///
/// Prior to semantic analysis, an initializer list will represent the
/// initializer list as written by the user, but will have the
/// placeholder type "void". This initializer list is called the
/// syntactic form of the initializer, and may contain C99 designated
/// initializers (represented as DesignatedInitExprs), initializations
/// of subobject members without explicit braces, and so on. Clients
/// interested in the original syntax of the initializer list should
/// use the syntactic form of the initializer list.
///
/// After semantic analysis, the initializer list will represent the
/// semantic form of the initializer, where the initializations of all
/// subobjects are made explicit with nested InitListExpr nodes and
/// C99 designators have been eliminated by placing the designated
/// initializations into the subobject they initialize. Additionally,
/// any "holes" in the initialization, where no initializer has been
/// specified for a particular subobject, will be replaced with
/// implicitly-generated CXXZeroInitValueExpr expressions that
/// value-initialize the subobjects. Note, however, that the
/// initializer lists may still have fewer initializers than there are
/// elements to initialize within the object.
///
/// Given the semantic form of the initializer list, one can retrieve
/// the original syntactic form of that initializer list (if it
/// exists) using getSyntacticForm(). Since many initializer lists
/// have the same syntactic and semantic forms, getSyntacticForm() may
/// return NULL, indicating that the current initializer list also
/// serves as its syntactic form.
class InitListExpr : public Expr {
std::vector<Stmt *> InitExprs;
SourceLocation LBraceLoc, RBraceLoc;
/// HadDesignators - Return true if there were any designators in this
/// init list expr. FIXME: this should be replaced by storing the designators
/// somehow and updating codegen.
bool HadDesignators;
/// Contains the initializer list that describes the syntactic form
/// written in the source code.
InitListExpr *SyntacticForm;
public:
InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits,
SourceLocation rbraceloc, bool HadDesignators);
SourceLocation rbraceloc);
unsigned getNumInits() const { return InitExprs.size(); }
bool hadDesignators() const { return HadDesignators; }
const Expr* getInit(unsigned Init) const {
assert(Init < getNumInits() && "Initializer access out of range!");
return cast<Expr>(InitExprs[Init]);
return cast_or_null<Expr>(InitExprs[Init]);
}
Expr* getInit(unsigned Init) {
assert(Init < getNumInits() && "Initializer access out of range!");
return cast<Expr>(InitExprs[Init]);
return cast_or_null<Expr>(InitExprs[Init]);
}
void setInit(unsigned Init, Expr *expr) {
@ -1668,13 +1689,22 @@ public:
InitExprs[Init] = expr;
}
// Dynamic removal/addition (for constructing implicit InitExpr's).
void removeInit(unsigned Init) {
InitExprs.erase(InitExprs.begin()+Init);
}
void addInit(unsigned Init, Expr *expr) {
InitExprs.insert(InitExprs.begin()+Init, expr);
}
/// @brief Specify the number of initializers
///
/// If there are more than @p NumInits initializers, the remaining
/// initializers will be destroyed. If there are fewer than @p
/// NumInits initializers, NULL expressions will be added for the
/// unknown initializers.
void resizeInits(ASTContext &Context, unsigned NumInits);
/// @brief Updates the initializer at index @p Init with the new
/// expression @p expr, and returns the old expression at that
/// location.
///
/// When @p Init is out of range for this initializer list, the
/// initializer list will be extended with NULL expressions to
/// accomodate the new entry.
Expr *updateInit(unsigned Init, Expr *expr);
// Explicit InitListExpr's originate from source code (and have valid source
// locations). Implicit InitListExpr's are created by the semantic analyzer.
@ -1682,6 +1712,13 @@ public:
return LBraceLoc.isValid() && RBraceLoc.isValid();
}
/// @brief Retrieve the initializer list that describes the
/// syntactic form of the initializer.
///
///
InitListExpr *getSyntacticForm() const { return SyntacticForm; }
void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; }
virtual SourceRange getSourceRange() const {
return SourceRange(LBraceLoc, RBraceLoc);
}
@ -1885,6 +1922,13 @@ public:
"Only valid on an array-range designator");
return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc);
}
SourceLocation getStartLocation() const {
if (Kind == FieldDesignator)
return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc();
else
return getLBracketLoc();
}
};
static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,

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

@ -477,6 +477,12 @@ public:
SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
/// @brief Whether this initialization expression was
/// implicitly-generated.
bool isImplicit() const {
return TyBeginLoc.isInvalid() && RParenLoc.isInvalid();
}
virtual SourceRange getSourceRange() const {
return SourceRange(TyBeginLoc, RParenLoc);
}

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

@ -50,8 +50,20 @@ DIAG(err_field_designator_nonfield, ERROR,
"field designator %0 does not refer to a non-static data member")
DIAG(note_field_designator_found, NOTE,
"field designator refers here")
DIAG(err_field_designator_anon_class, ERROR,
"field designator %0 refers to a member of an anonymous %select{struct|class|union}1")
DIAG(err_designator_for_scalar_init, ERROR,
"designator in initializer for scalar type %0")
DIAG(warn_subobject_initializer_overrides, WARNING,
"subobject initialization overrides initialization of other fields within its enclosing subobject")
DIAG(warn_initializer_overrides, WARNING,
"initializer overrides prior initialization of this subobject")
DIAG(note_previous_initializer, NOTE,
"previous initialization %select{|with side effects }0is here%select{| (side effects may not occur at run time)}0")
DIAG(warn_gnu_array_range_designator_unsupported, WARNING,
"GNU array-range designator extension is unsupported")
DIAG(warn_designator_into_union_broken_init, WARNING,
"designated initialization of union member is broken")
// Declarations.
DIAG(ext_vla, EXTENSION,

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

@ -221,13 +221,31 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
InitListExpr::InitListExpr(SourceLocation lbraceloc,
Expr **initExprs, unsigned numInits,
SourceLocation rbraceloc, bool hadDesignators)
SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType()),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), HadDesignators(hadDesignators) {
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) {
InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
}
void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) {
for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); Idx < LastIdx; ++Idx)
delete InitExprs[Idx];
InitExprs.resize(NumInits, 0);
}
Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
if (Init >= InitExprs.size()) {
InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0);
InitExprs.back() = expr;
return 0;
}
Expr *Result = cast_or_null<Expr>(InitExprs[Init]);
InitExprs[Init] = expr;
return Result;
}
/// getFunctionType - Return the underlying function type for this block.
///
const FunctionType *BlockExpr::getFunctionType() const {
@ -740,6 +758,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
return isEvaluatable(Ctx);
}
bool Expr::hasSideEffects(ASTContext &Ctx) const {
EvalResult Result;
Evaluate(Result, Ctx);
return Result.HasSideEffects;
}
/// isIntegerConstantExpr - this recursive routine will test if an expression is
/// an integer constant expression. Note: With the introduction of VLA's in
/// C99 the result of the sizeof operator is no longer always a constant

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

@ -872,13 +872,38 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
OS << "{ ";
for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
if (i) OS << ", ";
PrintExpr(Node->getInit(i));
if (Node->getInit(i))
PrintExpr(Node->getInit(i));
else
OS << "0";
}
OS << " }";
}
void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
// FIXME!
for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(),
DEnd = Node->designators_end();
D != DEnd; ++D) {
if (D->isFieldDesignator()) {
if (D->getDotLoc().isInvalid())
OS << D->getFieldName()->getName() << ":";
else
OS << "." << D->getFieldName()->getName();
} else {
OS << "[";
if (D->isArrayDesignator()) {
PrintExpr(Node->getArrayIndex(*D));
} else {
PrintExpr(Node->getArrayRangeStart(*D));
OS << " ... ";
PrintExpr(Node->getArrayRangeEnd(*D));
}
OS << "]";
}
}
OS << " = ";
PrintExpr(Node->getInit());
}
void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
@ -1187,7 +1212,9 @@ void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
//===----------------------------------------------------------------------===//
void Stmt::dumpPretty() const {
printPretty(llvm::errs());
llvm::raw_ostream &OS = llvm::errs();
printPretty(OS);
OS.flush();
}
void Stmt::printPretty(llvm::raw_ostream &OS, PrinterHelper* Helper) const {

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

@ -71,7 +71,7 @@ public:
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
EmitAggLoadOfLValue(E);
}
// Operators.
// case Expr::UnaryOperatorClass:
// case Expr::CastExprClass:
@ -303,11 +303,6 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
}
void AggExprEmitter::EmitNonConstInit(InitListExpr *E) {
if (E->hadDesignators()) {
CGF.ErrorUnsupported(E, "initializer list with designators");
return;
}
const llvm::PointerType *APType =
cast<llvm::PointerType>(DestPtr->getType());
const llvm::Type *DestType = APType->getElementType();
@ -346,6 +341,8 @@ void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
// FIXME: Are initializers affected by volatile?
if (E->getType()->isComplexType()) {
CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
} else if (isa<CXXZeroInitValueExpr>(E)) {
EmitNullInitializationToLValue(LV, E->getType());
} else if (CGF.hasAggregateLLVMType(E->getType())) {
CGF.EmitAnyExpr(E, LV.getAddress(), false);
} else {
@ -380,11 +377,6 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
}
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (E->hadDesignators()) {
CGF.ErrorUnsupported(E, "initializer list with designators");
return;
}
#if 0
// FIXME: Disabled while we figure out what to do about
// test/CodeGen/bitfield.c
@ -426,7 +418,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
uint64_t NumArrayElements = AType->getNumElements();
QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
ElementType =CGF.getContext().getAsArrayType(ElementType)->getElementType();
ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
unsigned CVRqualifier = ElementType.getCVRQualifiers();
@ -479,7 +471,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
}
// Unions only initialize one field.
// (things can get weird with designators, but they aren't
// (FIXME: things can get weird with designators, but they aren't
// supported yet.)
if (isUnion)
break;

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

@ -242,6 +242,8 @@ public:
const llvm::Type *Ty = ConvertType(ILE->getType());
// Find the field decl we're initializing, if any
// FIXME: C99 designated initializers won't always initialize the
// first field
int FieldNo = 0; // Field no in RecordDecl
FieldDecl* curField = 0;
for (RecordDecl::field_iterator Field = RD->field_begin(),
@ -304,12 +306,6 @@ public:
return llvm::Constant::getNullValue(RetTy);
}
// FIXME: We don't codegen or sema designators yet.
if (ILE->hadDesignators()) {
CGM.ErrorUnsupported(ILE, "initializer list with designators");
return llvm::UndefValue::get(ConvertType(ILE->getType()));
}
if (ILE->getType()->isArrayType())
return EmitArrayInitialization(ILE);

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

@ -176,11 +176,6 @@ public:
if (!VType)
return Visit(E->getInit(0));
if (E->hadDesignators()) {
CGF.ErrorUnsupported(E, "initializer list with designators");
return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
}
unsigned NumVectorElements = VType->getNumElements();
const llvm::Type *ElementType = VType->getElementType();

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

@ -28,6 +28,7 @@
#include "llvm/ADT/OwningPtr.h"
#include <string>
#include <vector>
#include <map>
namespace llvm {
class APSInt;
@ -1835,38 +1836,67 @@ private:
class InitListChecker {
Sema *SemaRef;
bool hadError;
std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
unsigned &Index);
unsigned &Index, InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex);
void CheckExplicitInitList(InitListExpr *IList, QualType &T,
unsigned &Index);
unsigned &Index, InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex);
void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index);
unsigned &Index,
InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex);
void CheckSubElementType(InitListExpr *IList, QualType ElemType,
Expr *expr, unsigned &Index);
Expr *expr, unsigned &Index,
InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex);
// FIXME: Does DeclType need to be a reference type?
void CheckScalarType(InitListExpr *IList, QualType &DeclType,
Expr *expr, unsigned &Index);
void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index);
Expr *expr, unsigned &Index,
InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex);
void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex);
void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index);
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex);
void CheckArrayType(InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext, unsigned &Index);
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex);
bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
DesignatedInitExpr::designators_iterator D,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
llvm::APSInt *NextElementIndex,
unsigned &Index);
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
QualType CurrentObjectType,
InitListExpr *StructuredList,
unsigned StructuredIndex,
SourceRange InitRange);
void UpdateStructuredListElement(InitListExpr *StructuredInitList,
unsigned &StructuredInitIndex,
Expr *expr);
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
public:
InitListChecker(Sema *S, InitListExpr *IL, QualType &T);
bool HadError() { return hadError; }
// @brief Retrieves the fully-structured initializer list used for
// semantic analysis and code generation.
InitListExpr *getFullyStructuredList() const { return FullyStructuredList; }
};
/// BlockSemaInfo - When a block is being parsed, this contains information

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

@ -1136,6 +1136,9 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
}
InitListChecker CheckInitList(this, InitList, DeclType);
if (!CheckInitList.HadError())
Init = CheckInitList.getFullyStructuredList();
return CheckInitList.HadError();
}
@ -2209,6 +2212,12 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
for (unsigned i = 0; i < numInits; i++) {
// FIXME: Need to get the type of the declaration for C++,
// because it could be a reference?
// Implicitly-generated value initializations are okay.
if (isa<CXXZeroInitValueExpr>(Exp->getInit(i)) &&
cast<CXXZeroInitValueExpr>(Exp->getInit(i))->isImplicit())
continue;
if (CheckForConstantInitializer(Exp->getInit(i),
Exp->getInit(i)->getType()))
return true;

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

@ -1985,7 +1985,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
// CheckInitializer() - it requires knowledge of the object being intialized.
InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit,
RBraceLoc, Designators.hasAnyDesignators());
RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
return Owned(E);
}
@ -3988,8 +3988,7 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
// Otherwise, create a compound literal expression as the base, and
// iteratively process the offsetof designators.
InitListExpr *IList =
new (Context) InitListExpr(SourceLocation(), 0, 0,
SourceLocation(), false);
new (Context) InitListExpr(SourceLocation(), 0, 0, SourceLocation());
IList->setType(ArgTy);
Expr *Res =
new (Context) CompoundLiteralExpr(SourceLocation(), ArgTy, IList, false);

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

@ -15,19 +15,73 @@
#include "clang/Parse/Designator.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/DiagnosticSema.h"
#include <algorithm> // for std::count_if
#include <functional> // for std::mem_fun
using namespace clang;
/// Recursively replaces NULL values within the given initializer list
/// with expressions that perform value-initialization of the
/// appropriate type.
static void fillInValueInitializations(ASTContext &Context, InitListExpr *ILE) {
assert((ILE->getType() != Context.VoidTy) && "Should not have void type");
if (const RecordType *RType = ILE->getType()->getAsRecordType()) {
unsigned Init = 0, NumInits = ILE->getNumInits();
for (RecordDecl::field_iterator Field = RType->getDecl()->field_begin(),
FieldEnd = RType->getDecl()->field_end();
Field != FieldEnd; ++Field) {
if (Field->isUnnamedBitfield())
continue;
if (Init >= NumInits)
break;
// FIXME: Check for fields with reference type in C++?
if (!ILE->getInit(Init))
ILE->setInit(Init,
new (Context) CXXZeroInitValueExpr(Field->getType(),
SourceLocation(),
SourceLocation()));
else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init)))
fillInValueInitializations(Context, InnerILE);
++Init;
}
return;
}
QualType ElementType;
if (const ArrayType *AType = Context.getAsArrayType(ILE->getType()))
ElementType = AType->getElementType();
else if (const VectorType *VType = ILE->getType()->getAsVectorType())
ElementType = VType->getElementType();
else
ElementType = ILE->getType();
for (unsigned Init = 0, NumInits = ILE->getNumInits(); Init != NumInits;
++Init) {
if (!ILE->getInit(Init))
ILE->setInit(Init, new (Context) CXXZeroInitValueExpr(ElementType,
SourceLocation(),
SourceLocation()));
else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init)))
fillInValueInitializations(Context, InnerILE);
}
}
InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
hadError = false;
SemaRef = S;
unsigned newIndex = 0;
unsigned newStructuredIndex = 0;
FullyStructuredList
= getStructuredSubobjectInit(IL, newIndex, T, 0, 0, SourceRange());
CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex);
CheckExplicitInitList(IL, T, newIndex);
if (!hadError) {
fillInValueInitializations(SemaRef->Context, FullyStructuredList);
}
}
int InitListChecker::numArrayElements(QualType DeclType) {
@ -42,17 +96,22 @@ int InitListChecker::numArrayElements(QualType DeclType) {
int InitListChecker::numStructUnionElements(QualType DeclType) {
RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
const int InitializableMembers
= std::count_if(structDecl->field_begin(), structDecl->field_end(),
std::mem_fun(&FieldDecl::getDeclName));
int InitializableMembers = 0;
for (RecordDecl::field_iterator Field = structDecl->field_begin(),
FieldEnd = structDecl->field_end();
Field != FieldEnd; ++Field) {
if ((*Field)->getIdentifier() || !(*Field)->isBitField())
++InitializableMembers;
}
if (structDecl->isUnion())
return std::min(InitializableMembers, 1);
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
QualType T, unsigned &Index) {
llvm::SmallVector<Expr*, 4> InitExprs;
QualType T, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
int maxElements = 0;
if (T->isArrayType())
@ -64,45 +123,39 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
else
assert(0 && "CheckImplicitInitList(): Illegal type");
// FIXME: Perhaps we should move this warning elsewhere?
if (maxElements == 0) {
SemaRef->Diag(ParentIList->getInit(Index)->getLocStart(),
diag::err_implicit_empty_initializer);
++Index;
hadError = true;
return;
}
// Check the element types *before* we create the implicit init list;
// otherwise, we might end up taking the wrong number of elements
unsigned NewIndex = Index;
CheckListElementTypes(ParentIList, T, false, NewIndex);
// Build a structured initializer list corresponding to this subobject.
InitListExpr *StructuredSubobjectInitList
= getStructuredSubobjectInit(ParentIList, Index, T, StructuredList,
StructuredIndex,
ParentIList->getInit(Index)->getSourceRange());
unsigned StructuredSubobjectInitIndex = 0;
for (int i = 0; i < maxElements; ++i) {
// Don't attempt to go past the end of the init list
if (Index >= ParentIList->getNumInits())
break;
Expr* expr = ParentIList->getInit(Index);
// Add the expr to the new implicit init list and remove if from the old.
InitExprs.push_back(expr);
ParentIList->removeInit(Index);
}
// Synthesize an "implicit" InitListExpr (marked by the invalid source locs).
InitListExpr *ILE = new InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation(),
ParentIList->hadDesignators());
ILE->setType(T);
// Modify the parent InitListExpr to point to the implicit InitListExpr.
ParentIList->addInit(Index, ILE);
// Check the element types and build the structural subobject.
CheckListElementTypes(ParentIList, T, false, Index,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
}
void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
unsigned &Index) {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
CheckListElementTypes(IList, T, true, Index);
SyntacticToSemantic[IList] = StructuredList;
StructuredList->setSyntacticForm(IList);
CheckListElementTypes(IList, T, true, Index, StructuredList,
StructuredIndex);
IList->setType(T);
StructuredList->setType(T);
if (hadError)
return;
@ -131,27 +184,31 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
void InitListChecker::CheckListElementTypes(InitListExpr *IList,
QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index) {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (DeclType->isScalarType()) {
CheckScalarType(IList, DeclType, 0, Index);
CheckScalarType(IList, DeclType, 0, Index, StructuredList, StructuredIndex);
} else if (DeclType->isVectorType()) {
CheckVectorType(IList, DeclType, Index);
CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
} else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
if (DeclType->isStructureType() || DeclType->isUnionType()) {
RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
SubobjectIsDesignatorContext, Index);
SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isArrayType()) {
llvm::APSInt Zero(
SemaRef->Context.getTypeSize(SemaRef->Context.getSizeType()),
false);
CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index);
CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
}
else
assert(0 && "Aggregate that isn't a function or array?!");
assert(0 && "Aggregate that isn't a structure or array?!");
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
// This type is invalid, issue a diagnostic.
Index++;
++Index;
SemaRef->Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
<< DeclType;
hadError = true;
@ -165,31 +222,46 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
void InitListChecker::CheckSubElementType(InitListExpr *IList,
QualType ElemType,
Expr *expr,
unsigned &Index) {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
unsigned newIndex = 0;
CheckExplicitInitList(SubInitList, ElemType, newIndex);
Index++;
unsigned newStructuredIndex = 0;
InitListExpr *newStructuredList
= getStructuredSubobjectInit(IList, Index, ElemType,
StructuredList, StructuredIndex,
SubInitList->getSourceRange());
CheckExplicitInitList(SubInitList, ElemType, newIndex,
newStructuredList, newStructuredIndex);
++StructuredIndex;
++Index;
} else if (StringLiteral *lit =
SemaRef->IsStringLiteralInit(expr, ElemType)) {
SemaRef->CheckStringLiteralInit(lit, ElemType);
Index++;
UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
++Index;
} else if (ElemType->isScalarType()) {
CheckScalarType(IList, ElemType, expr, Index);
CheckScalarType(IList, ElemType, expr, Index, StructuredList,
StructuredIndex);
} else if (expr->getType()->getAsRecordType() &&
SemaRef->Context.typesAreCompatible(
expr->getType().getUnqualifiedType(),
ElemType.getUnqualifiedType())) {
Index++;
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
// FIXME: Add checking
} else {
CheckImplicitInitList(IList, ElemType, Index);
Index++;
}
CheckImplicitInitList(IList, ElemType, Index, StructuredList,
StructuredIndex);
++StructuredIndex;
}
}
void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
Expr *expr, unsigned &Index) {
Expr *expr, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (Index < IList->getNumInits()) {
if (!expr)
expr = IList->getInit(Index);
@ -199,6 +271,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
<< IList->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
} else if (isa<DesignatedInitExpr>(expr)) {
SemaRef->Diag(expr->getSourceRange().getBegin(),
@ -206,6 +279,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
<< DeclType << expr->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
@ -219,18 +293,27 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
DIE->setInit(expr);
else
IList->setInit(Index, expr);
}
if (hadError)
++StructuredIndex;
else
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
} else {
SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
<< IList->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
}
void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
unsigned &Index) {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (Index < IList->getNumInits()) {
const VectorType *VT = DeclType->getAsVectorType();
int maxElements = VT->getNumElements();
@ -240,7 +323,8 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
break;
CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
StructuredList, StructuredIndex);
}
}
}
@ -248,12 +332,21 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext,
unsigned &Index) {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
// Check for the special-case of initializing an array with a string.
if (Index < IList->getNumInits()) {
if (StringLiteral *lit =
SemaRef->IsStringLiteralInit(IList->getInit(Index), DeclType)) {
SemaRef->CheckStringLiteralInit(lit, DeclType);
// We place the string literal directly into the resulting
// initializer list. This is the only place where the structure
// of the structured initializer list doesn't match exactly,
// because doing so would involve allocating one character
// constant for each string.
UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
StructuredList->resizeInits(SemaRef->Context, StructuredIndex);
++Index;
return;
}
@ -267,11 +360,14 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
diag::err_variable_object_no_init)
<< VAT->getSizeExpr()->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
// We might know the maximum number of elements in advance.
llvm::APSInt maxElements(elementIndex.getBitWidth(), elementIndex.isUnsigned());
llvm::APSInt maxElements(elementIndex.getBitWidth(),
elementIndex.isUnsigned());
bool maxElementsKnown = false;
if (const ConstantArrayType *CAT =
SemaRef->Context.getAsConstantArrayType(DeclType)) {
@ -295,7 +391,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
// Handle this designated initializer. elementIndex will be
// updated to be the next array element we'll initialize.
if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(),
DeclType, 0, &elementIndex, Index)) {
DeclType, 0, &elementIndex, Index,
StructuredList, StructuredIndex)) {
hadError = true;
continue;
}
@ -320,7 +417,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
break;
// Check this element.
CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
StructuredList, StructuredIndex);
++elementIndex;
// If the array is of incomplete type, keep track of the number of
@ -348,7 +446,9 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
QualType DeclType,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext,
unsigned &Index) {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
// If the record is invalid, some of it's members are invalid. To avoid
@ -376,7 +476,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(),
DeclType, &Field, 0, Index))
DeclType, &Field, 0, Index,
StructuredList, StructuredIndex))
hadError = true;
continue;
@ -391,13 +492,14 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
if (Field->getType()->isIncompleteArrayType())
break;
if (!Field->getIdentifier()) {
// Don't initialize unnamed fields, e.g. "int : 20;"
if (!Field->getIdentifier() && Field->isBitField()) {
// Don't initialize unnamed bitfields, e.g. "int : 20;"
++Field;
continue;
}
CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index);
CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index,
StructuredList, StructuredIndex);
if (DeclType->isUnionType()) // FIXME: designated initializers?
break;
@ -416,8 +518,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
/// IList, is well-formed for a current object of type @p DeclType
/// (C99 6.7.8). The actual subobject that this designator refers to
/// within the current subobject is returned in either
/// @p DesignatedField or @p DesignatedIndex (whichever is
/// appropriate).
/// @p NextField or @p NextElementIndex (whichever is appropriate).
///
/// @param IList The initializer list in which this designated
/// initializer occurs.
@ -439,6 +540,10 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
/// @param Index Index into @p IList where the designated initializer
/// @p DIE occurs.
///
/// @param StructuredList The initializer list expression that
/// describes all of the subobject initializers in the order they'll
/// actually be initialized.
///
/// @returns true if there was an error, false otherwise.
bool
InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
@ -447,16 +552,30 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
llvm::APSInt *NextElementIndex,
unsigned &Index) {
bool IsFirstDesignator = (D == DIE->designators_begin());
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (D == DIE->designators_end()) {
// Check the actual initialization for the designated object type.
bool prevHadError = hadError;
CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index);
CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index,
StructuredList, StructuredIndex);
return hadError && !prevHadError;
}
bool IsFirstDesignator = (D == DIE->designators_begin());
assert((IsFirstDesignator || StructuredList) &&
"Need a non-designated initializer list to start from");
// Determine the structural initializer list that corresponds to the
// current subobject.
StructuredList = IsFirstDesignator? SyntacticToSemantic[IList]
: getStructuredSubobjectInit(IList, Index, CurrentObjectType, StructuredList,
StructuredIndex,
SourceRange(D->getStartLocation(),
DIE->getSourceRange().getEnd()));
assert(StructuredList && "Expected a structured initializer list");
if (D->isFieldDesignator()) {
// C99 6.7.8p7:
//
@ -478,56 +597,95 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
return true;
}
// Note: we perform a linear search of the fields here, despite
// the fact that we have a faster lookup method, because we always
// need to compute the field's index.
IdentifierInfo *FieldName = D->getFieldName();
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
FieldDecl *DesignatedField = 0;
if (Lookup.first == Lookup.second) {
// Lookup did not find anything with this name.
SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
} else if (isa<FieldDecl>(*Lookup.first)) {
// Name lookup found a field.
DesignatedField = cast<FieldDecl>(*Lookup.first);
// FIXME: Make sure this isn't a field in an anonymous
// struct/union.
} else {
// Name lookup found something, but it wasn't a field.
SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
SemaRef->Diag((*Lookup.first)->getLocation(),
diag::note_field_designator_found);
unsigned FieldIndex = 0;
RecordDecl::field_iterator Field = RT->getDecl()->field_begin(),
FieldEnd = RT->getDecl()->field_end();
for (; Field != FieldEnd; ++Field) {
if (Field->isUnnamedBitfield())
continue;
if (Field->getIdentifier() == FieldName)
break;
++FieldIndex;
}
if (!DesignatedField) {
if (Field == FieldEnd) {
// We did not find the field we're looking for. Produce a
// suitable diagnostic and return a failure.
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
if (Lookup.first == Lookup.second) {
// Name lookup didn't find anything.
SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
} else {
// Name lookup found something, but it wasn't a field.
SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
SemaRef->Diag((*Lookup.first)->getLocation(),
diag::note_field_designator_found);
}
++Index;
return true;
} else if (cast<RecordDecl>((*Field)->getDeclContext())
->isAnonymousStructOrUnion()) {
SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_anon_class)
<< FieldName
<< (cast<RecordDecl>((*Field)->getDeclContext())->isUnion()? 2 :
(int)SemaRef->getLangOptions().CPlusPlus);
SemaRef->Diag((*Field)->getLocation(), diag::note_field_designator_found);
++Index;
return true;
}
// All of the fields of a union are located at the same place in
// the initializer list.
// FIXME: Need to tell CodeGen which type to initialize to. ImplicitCastExpr?
if (RT->getDecl()->isUnion() && FieldIndex != 0) {
SemaRef->Diag(D->getStartLocation(),
diag::warn_designator_into_union_broken_init)
<< SourceRange(D->getStartLocation(), DIE->getSourceRange().getEnd());
FieldIndex = 0;
}
// Update the designator with the field declaration.
D->setField(DesignatedField);
D->setField(*Field);
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this field.
if (FieldIndex >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef->Context, FieldIndex + 1);
// Recurse to check later designated subobjects.
QualType FieldType = DesignatedField->getType();
if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index))
QualType FieldType = (*Field)->getType();
unsigned newStructuredIndex = FieldIndex;
if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index,
StructuredList, newStructuredIndex))
return true;
// Find the position of the next field to be initialized in this
// subobject.
RecordDecl::field_iterator Field(DeclContext::decl_iterator(DesignatedField),
RT->getDecl()->decls_end());
++Field;
++FieldIndex;
// If this the first designator, our caller will continue checking
// the rest of this struct/class/union subobject.
if (IsFirstDesignator) {
if (NextField)
*NextField = Field;
StructuredIndex = FieldIndex;
return false;
}
// Check the remaining fields within this class/struct/union subobject.
bool prevHadError = hadError;
CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index);
CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
StructuredList, FieldIndex);
return hadError && !prevHadError;
}
@ -561,6 +719,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
else {
assert(D->isArrayRangeDesignator() && "Need array-range designator");
IndexExpr = DIE->getArrayRangeEnd(*D);
SemaRef->Diag(D->getEllipsisLoc(),
diag::warn_gnu_array_range_designator_unsupported)
<< SourceRange(D->getLBracketLoc(), D->getRBracketLoc());
}
bool ConstExpr
@ -581,28 +742,115 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
}
}
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this array element.
unsigned ElementIndex = DesignatedIndex.getZExtValue();
if (ElementIndex >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef->Context, ElementIndex + 1);
// Recurse to check later designated subobjects.
QualType ElementType = AT->getElementType();
if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index))
if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index,
StructuredList, ElementIndex))
return true;
// Move to the next index in the array that we'll be initializing.
++DesignatedIndex;
ElementIndex = DesignatedIndex.getZExtValue();
// If this the first designator, our caller will continue checking
// the rest of this array subobject.
if (IsFirstDesignator) {
if (NextElementIndex)
*NextElementIndex = DesignatedIndex;
StructuredIndex = ElementIndex;
return false;
}
// Check the remaining elements within this array subobject.
bool prevHadError = hadError;
CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index);
CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index,
StructuredList, ElementIndex);
return hadError && !prevHadError;
}
// Get the structured initializer list for a subobject of type
// @p CurrentObjectType.
InitListExpr *
InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
QualType CurrentObjectType,
InitListExpr *StructuredList,
unsigned StructuredIndex,
SourceRange InitRange) {
Expr *ExistingInit = 0;
if (!StructuredList)
ExistingInit = SyntacticToSemantic[IList];
else if (StructuredIndex < StructuredList->getNumInits())
ExistingInit = StructuredList->getInit(StructuredIndex);
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
return Result;
if (ExistingInit) {
// We are creating an initializer list that initializes the
// subobjects of the current object, but there was already an
// initialization that completely initialized the current
// subobject, e.g., by a compound literal:
//
// struct X { int a, b; };
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
// Here, xs[0].a == 0 and xs[0].b == 3, since the second,
// designated initializer re-initializes the whole
// subobject [0], overwriting previous initializers.
SemaRef->Diag(InitRange.getBegin(), diag::warn_subobject_initializer_overrides)
<< InitRange;
SemaRef->Diag(ExistingInit->getSourceRange().getBegin(),
diag::note_previous_initializer)
<< ExistingInit->hasSideEffects(SemaRef->Context)
<< ExistingInit->getSourceRange();
}
InitListExpr *Result
= new (SemaRef->Context) InitListExpr(SourceLocation(), 0, 0,
SourceLocation());
Result->setType(CurrentObjectType);
// Link this new initializer list into the structured initializer
// lists.
if (StructuredList)
StructuredList->updateInit(StructuredIndex, Result);
else {
Result->setSyntacticForm(IList);
SyntacticToSemantic[IList] = Result;
}
return Result;
}
/// Update the initializer at index @p StructuredIndex within the
/// structured initializer list to the value @p expr.
void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
unsigned &StructuredIndex,
Expr *expr) {
// No structured initializer list to update
if (!StructuredList)
return;
if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
SemaRef->Diag(expr->getSourceRange().getBegin(),
diag::warn_initializer_overrides)
<< expr->getSourceRange();
SemaRef->Diag(PrevInit->getSourceRange().getBegin(),
diag::note_previous_initializer)
<< (int)PrevInit->hasSideEffects(SemaRef->Context)
<< PrevInit->getSourceRange();
}
++StructuredIndex;
}
/// Check that the given Index expression is a valid array designator
/// value. This is essentailly just a wrapper around
/// Expr::isIntegerConstantExpr that also checks for negative values

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

@ -1,4 +1,4 @@
// RUN: clang -fsyntax-only -verify -pedantic %s
// RUN: clang -fsyntax-only -pedantic -verify %s
extern int foof() = 1; // expected-error{{illegal initializer (only variables can be initialized)}}
@ -101,6 +101,7 @@ void legal() {
{ 2, 3 },
{ 4, 5, 6 }
};
int q_sizecheck[(sizeof(q) / sizeof(short [3][2])) == 3? 1 : -1];
}
unsigned char asso_values[] = { 34 };
@ -134,15 +135,19 @@ typedef int AryT[];
void testTypedef()
{
AryT a = { 1, 2 }, b = { 3, 4, 5 };
int a_sizecheck[(sizeof(a) / sizeof(int)) == 2? 1 : -1];
int b_sizecheck[(sizeof(b) / sizeof(int)) == 3? 1 : -1];
}
static char const xx[] = "test";
int xx_sizecheck[(sizeof(xx) / sizeof(char)) == 5? 1 : -1];
static char const yy[5] = "test";
static char const zz[3] = "test"; // expected-warning{{initializer-string for char array is too long}}
void charArrays()
{
static char const test[] = "test";
int test_sizecheck[(sizeof(test) / sizeof(char)) == 5? 1 : -1];
static char const test2[] = { "weird stuff" };
static char const test3[] = { "test", "excess stuff" }; // expected-error{{excess elements in char array initializer}}
@ -171,6 +176,7 @@ void variableArrayInit() {
float r1[10] = {{7}}; //expected-warning{{braces around scalar initializer}}
float r2[] = {{8}}; //expected-warning{{braces around scalar initializer}}
char r3[][5] = {1,2,3,4,5,6};
int r3_sizecheck[(sizeof(r3) / sizeof(char[5])) == 2? 1 : -1];
char r3_2[sizeof r3 == 10 ? 1 : -1];
float r4[1][2] = {1,{2},3,4}; //expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in array initializer}}
char r5[][5] = {"aa", "bbb", "ccccc"};
@ -195,7 +201,7 @@ int bar (void) {
return z.z;
}
struct s3 {void (*a)(void);} t5 = {autoStructTest};
// GCC extension; flexible array init. Once this is implemented, the warning should be removed.
// FIXME: GCC extension; flexible array init. Once this is implemented, the warning should be removed.
// Note that clang objc implementation depends on this extension.
struct {int a; int b[];} t6 = {1, {1, 2, 3}}; //expected-warning{{excess elements in array initializer}}
union {char a; int b;} t7[] = {1, 2, 3};
@ -238,3 +244,21 @@ struct soft_segment_descriptor gdt_segs[] = {
static void sppp_ipv6cp_up();
const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-warning{{excess elements in array initializer}}
struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a GNU extension in C}}
typedef struct _Matrix Matrix;
void test_matrix() {
const Matrix mat1 = {
{ { 1.0f, 2.0f, 3.0f, 4.0f,
5.0f, 6.0f, 7.0f, 8.0f,
9.0f, 10.0f, 11.0f, 12.0f,
13.0f, 14.0f, 15.0f, 16.0f } }
};
const Matrix mat2 = {
1.0f, 2.0f, 3.0f, 4.0f,
5.0f, 6.0f, 7.0f, 8.0f,
9.0f, 10.0f, 11.0f, 12.0f,
13.0f, 14.0f, 15.0f, 16.0f
};
}

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

@ -18,7 +18,8 @@ int iarray2[10] = {
};
int iarray3[10] = {
[5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}
[5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}\
// expected-warning{{GNU array-range designator extension is unsupported}}
};
struct point {
@ -44,8 +45,8 @@ struct point array[10] = {
struct point array2[10] = {
[10].x = 2.0, // expected-error{{array designator index (10) exceeds array bounds (10)}}
[4 ... 5].y = 2.0,
[4 ... 6] = { .x = 3, .y = 4.0 }
[4 ... 5].y = 2.0, // expected-warning{{GNU array-range designator extension is unsupported}}
[4 ... 6] = { .x = 3, .y = 4.0 } // expected-warning{{GNU array-range designator extension is unsupported}}
};
struct point array3[10] = {
@ -116,4 +117,25 @@ struct disklabel_ops disklabel64_ops = {
// PR clang/3378
int bitwidth[] = { [(long long int)1] = 5, [(short int)2] = 2 };
int a[]= { [sizeof(int)] = 0 };
int a2[]= { [0 ... sizeof(int)] = 0 };
int a2[]= { [0 ... sizeof(int)] = 0 }; // expected-warning{{GNU array-range designator extension is unsupported}}
// Test warnings about initializers overriding previous initializers
struct X {
int a, b, c;
};
int counter = 0;
int get8() { ++counter; return 8; }
void test() {
struct X xs[] = {
[0] = (struct X){1, 2}, // expected-note{{previous initialization is here}}
[0].c = 3, // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
(struct X) {4, 5, 6}, // expected-note{{previous initialization is here}}
[1].b = get8(), // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
[0].b = 8
};
}
// FIXME: we need to
union { char c; long l; } u1 = { .l = 0xFFFF }; // expected-warning{{designated initialization of union member is broken}}

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

@ -1,5 +1,15 @@
// RUN: clang %s -verify -fsyntax-only
// RUN: clang %s -fsyntax-only -verify
typedef __attribute__(( ext_vector_type(4) )) float float4;
//typedef float float4 __attribute__((vector_size(16)));
float4 foo = (float4){ 1.0, 2.0, 3.0, 4.0 };
float4 array[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
int array_sizecheck[(sizeof(array) / sizeof(float4)) == 3? 1 : -1];
float4 array2[2] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
9.0 }; // expected-warning {{excess elements in array initializer}}
float4 array3[2] = { {1.0, 2.0, 3.0}, 5.0, 6.0, 7.0, 8.0,
9.0 }; // expected-warning {{excess elements in array initializer}}