Implement support for designated initializers that refer to members of

anonymous structs or unions. Fixes PR3778.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69153 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-04-15 06:41:24 +00:00
Родитель 3ac86b59b0
Коммит ffb4b6e299
7 изменённых файлов: 224 добавлений и 53 удалений

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

@ -1963,6 +1963,11 @@ private:
/// 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 {
public:
/// \brief Forward declaration of the Designator class.
class Designator;
private:
/// The location of the '=' or ':' prior to the actual initializer
/// expression.
SourceLocation EqualOrColonLoc;
@ -1974,17 +1979,20 @@ class DesignatedInitExpr : public Expr {
/// The number of designators in this initializer expression.
unsigned NumDesignators : 15;
/// \brief The designators in this designated initialization
/// expression.
Designator *Designators;
/// 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,
const Designator *Designators,
SourceLocation EqualOrColonLoc, bool GNUSyntax,
unsigned NumSubExprs)
: Expr(DesignatedInitExprClass, Ty),
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) { }
unsigned NumSubExprs);
public:
/// A field designator, e.g., ".x".
@ -2041,6 +2049,8 @@ public:
friend class DesignatedInitExpr;
public:
Designator() {}
/// @brief Initializes a field designator.
Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc,
SourceLocation FieldLoc)
@ -2136,8 +2146,10 @@ public:
// Iterator access to the designators.
typedef Designator* designators_iterator;
designators_iterator designators_begin();
designators_iterator designators_end();
designators_iterator designators_begin() { return Designators; }
designators_iterator designators_end() {
return Designators + NumDesignators;
}
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
@ -2162,8 +2174,15 @@ public:
*child_begin() = init;
}
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
void ExpandDesignator(unsigned Idx, const Designator *First,
const Designator *Last);
virtual SourceRange getSourceRange() const;
virtual void Destroy(ASTContext &C);
static bool classof(const Stmt *T) {
return T->getStmtClass() == DesignatedInitExprClass;
}

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

@ -49,9 +49,6 @@ def err_field_designator_unknown : Error<
def err_field_designator_nonfield : Error<
"field designator %0 does not refer to a non-static data member">;
def note_field_designator_found : Note<"field designator refers here">;
def err_field_designator_anon_class : Error<
"field designator %0 refers to a member of an anonymous "
"%select{struct|class|union}1">;
def err_designator_for_scalar_init : Error<
"designator in initializer for scalar type %0">;
def warn_subobject_initializer_overrides : Warning<

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

@ -20,6 +20,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include <algorithm>
using namespace clang;
//===----------------------------------------------------------------------===//
@ -1499,6 +1500,19 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
return getField()->getIdentifier();
}
DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc,
bool GNUSyntax,
unsigned NumSubExprs)
: Expr(DesignatedInitExprClass, Ty),
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) {
this->Designators = new Designator[NumDesignators];
for (unsigned I = 0; I != NumDesignators; ++I)
this->Designators[I] = Designators[I];
}
DesignatedInitExpr *
DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
unsigned NumDesignators,
@ -1506,10 +1520,9 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
SourceLocation ColonOrEqualLoc,
bool UsesColonSyntax, Expr *Init) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
sizeof(Designator) * NumDesignators +
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
DesignatedInitExpr *DIE
= new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators,
= new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators,
ColonOrEqualLoc, UsesColonSyntax,
NumIndexExprs + 1);
@ -1517,7 +1530,6 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *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())
@ -1549,22 +1561,10 @@ SourceRange DesignatedInitExpr::getSourceRange() const {
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));
}
@ -1574,7 +1574,6 @@ Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
"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));
}
@ -1584,11 +1583,43 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
"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));
}
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
const Designator *First,
const Designator *Last) {
unsigned NumNewDesignators = Last - First;
if (NumNewDesignators == 0) {
std::copy_backward(Designators + Idx + 1,
Designators + NumDesignators,
Designators + Idx);
--NumNewDesignators;
return;
} else if (NumNewDesignators == 1) {
Designators[Idx] = *First;
return;
}
Designator *NewDesignators
= new Designator[NumDesignators - 1 + NumNewDesignators];
std::copy(Designators, Designators + Idx, NewDesignators);
std::copy(First, Last, NewDesignators + Idx);
std::copy(Designators + Idx + 1, Designators + NumDesignators,
NewDesignators + Idx + NumNewDesignators);
delete [] Designators;
Designators = NewDesignators;
NumDesignators = NumDesignators - 1 + NumNewDesignators;
}
void DesignatedInitExpr::Destroy(ASTContext &C) {
delete [] Designators;
Expr::Destroy(C);
}
//===----------------------------------------------------------------------===//
// ExprIterator.
//===----------------------------------------------------------------------===//
@ -1774,7 +1805,6 @@ Stmt::child_iterator InitListExpr::child_end() {
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() {

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

@ -1226,6 +1226,8 @@ public:
DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
bool TypeDependent, bool ValueDependent,
const CXXScopeSpec *SS = 0);
VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
llvm::SmallVectorImpl<FieldDecl *> &Path);
OwningExprResult
BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
FieldDecl *Field,

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

@ -486,29 +486,33 @@ static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
return 0;
}
Sema::OwningExprResult
Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
FieldDecl *Field,
Expr *BaseObjectExpr,
SourceLocation OpLoc) {
/// \brief Given a field that represents a member of an anonymous
/// struct/union, build the path from that field's context to the
/// actual member.
///
/// Construct the sequence of field member references we'll have to
/// perform to get to the field in the anonymous union/struct. The
/// list of members is built from the field outward, so traverse it
/// backwards to go from an object in the current context to the field
/// we found.
///
/// \returns The variable from which the field access should begin,
/// for an anonymous struct/union that is not a member of another
/// class. Otherwise, returns NULL.
VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
llvm::SmallVectorImpl<FieldDecl *> &Path) {
assert(Field->getDeclContext()->isRecord() &&
cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()
&& "Field must be stored inside an anonymous struct or union");
// Construct the sequence of field member references
// we'll have to perform to get to the field in the anonymous
// union/struct. The list of members is built from the field
// outward, so traverse it backwards to go from an object in
// the current context to the field we found.
llvm::SmallVector<FieldDecl *, 4> AnonFields;
AnonFields.push_back(Field);
Path.push_back(Field);
VarDecl *BaseObject = 0;
DeclContext *Ctx = Field->getDeclContext();
do {
RecordDecl *Record = cast<RecordDecl>(Ctx);
Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record);
if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject))
AnonFields.push_back(AnonField);
Path.push_back(AnonField);
else {
BaseObject = cast<VarDecl>(AnonObject);
break;
@ -517,6 +521,18 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
} while (Ctx->isRecord() &&
cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
return BaseObject;
}
Sema::OwningExprResult
Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
FieldDecl *Field,
Expr *BaseObjectExpr,
SourceLocation OpLoc) {
llvm::SmallVector<FieldDecl *, 4> AnonFields;
VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
AnonFields);
// Build the expression that refers to the base object, from
// which we will build a sequence of member references to each
// of the anonymous union objects and, eventually, the field we

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

@ -1031,6 +1031,64 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
StructuredIndex);
}
/// \brief Expand a field designator that refers to a member of an
/// anonymous struct or union into a series of field designators that
/// refers to the field within the appropriate subobject.
///
/// Field/FieldIndex will be updated to point to the (new)
/// currently-designated field.
static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
DesignatedInitExpr *DIE,
unsigned DesigIdx,
FieldDecl *Field,
RecordDecl::field_iterator &FieldIter,
unsigned &FieldIndex) {
typedef DesignatedInitExpr::Designator Designator;
// Build the path from the current object to the member of the
// anonymous struct/union (backwards).
llvm::SmallVector<FieldDecl *, 4> Path;
SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path);
// Build the replacement designators.
llvm::SmallVector<Designator, 4> Replacements;
for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
FI = Path.rbegin(), FIEnd = Path.rend();
FI != FIEnd; ++FI) {
if (FI + 1 == FIEnd)
Replacements.push_back(Designator((IdentifierInfo *)0,
DIE->getDesignator(DesigIdx)->getDotLoc(),
DIE->getDesignator(DesigIdx)->getFieldLoc()));
else
Replacements.push_back(Designator((IdentifierInfo *)0, SourceLocation(),
SourceLocation()));
Replacements.back().setField(*FI);
}
// Expand the current designator into the set of replacement
// designators, so we have a full subobject path down to where the
// member of the anonymous struct/union is actually stored.
DIE->ExpandDesignator(DesigIdx, &Replacements[0],
&Replacements[0] + Replacements.size());
// Update FieldIter/FieldIndex;
RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext());
FieldIter = Record->field_begin(SemaRef.Context);
FieldIndex = 0;
for (RecordDecl::field_iterator FEnd = Record->field_end(SemaRef.Context);
FieldIter != FEnd; ++FieldIter) {
if (FieldIter->isUnnamedBitfield())
continue;
if (*FieldIter == Path.back())
return;
++FieldIndex;
}
assert(false && "Unable to find anonymous struct/union field");
}
/// @brief Check the well-formedness of a C99 designated initializer.
///
/// Determines whether the designated initializer @p DIE, which
@ -1138,6 +1196,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// 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.
FieldDecl *KnownField = D->getField();
IdentifierInfo *FieldName = D->getFieldName();
unsigned FieldIndex = 0;
RecordDecl::field_iterator
@ -1147,40 +1206,50 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
if (Field->isUnnamedBitfield())
continue;
if (Field->getIdentifier() == FieldName)
if (KnownField == *Field || Field->getIdentifier() == FieldName)
break;
++FieldIndex;
}
if (Field == FieldEnd) {
// We did not find the field we're looking for. Produce a
// suitable diagnostic and return a failure.
// There was no normal field in the struct with the designated
// name. Perform another lookup for this name, which may find
// something that we can't designate (e.g., a member function),
// may find nothing, or may find a member of an anonymous
// struct/union.
DeclContext::lookup_result Lookup
= RT->getDecl()->lookup(SemaRef.Context, FieldName);
if (Lookup.first == Lookup.second) {
// Name lookup didn't find anything.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
++Index;
return true;
} else if (!KnownField && isa<FieldDecl>(*Lookup.first) &&
cast<RecordDecl>((*Lookup.first)->getDeclContext())
->isAnonymousStructOrUnion()) {
// Handle an field designator that refers to a member of an
// anonymous struct or union.
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
cast<FieldDecl>(*Lookup.first),
Field, FieldIndex);
} 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())
}
} else if (!KnownField &&
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;
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, *Field,
Field, FieldIndex);
D = DIE->getDesignator(DesigIdx);
}
// All of the fields of a union are located at the same place in
@ -1284,6 +1353,10 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
if (!FinishSubobjectInit)
return false;
// We've already initialized something in the union; we're done.
if (RT->getDecl()->isUnion())
return hadError;
// Check the remaining fields within this class/struct/union subobject.
bool prevHadError = hadError;
CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,

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

@ -187,3 +187,37 @@ const union wibble wobble = { .arr2[0] = 0xffff,
.arr2[2] = 0xffff };
const union wibble wobble2 = { .arr2 = {4, 5, 6}, 7 }; // expected-warning{{excess elements in union initializer}}
// PR3778
struct s {
union { int i; };
};
struct s si = {
{ .i = 1 }
};
double d0;
char c0;
float f0;
int i0;
struct Enigma {
union {
struct {
struct {
double *double_ptr;
char *string;
};
float *float_ptr;
};
int *int_ptr;
};
char *string2;
};
struct Enigma enigma = {
.double_ptr = &d0, &c0,
&f0, // expected-note{{previous}}
&c0,
.float_ptr = &f0 // expected-warning{{overrides}}
};