summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Expr.cpp66
-rw-r--r--clang/lib/Sema/Sema.h2
-rw-r--r--clang/lib/Sema/SemaExpr.cpp44
-rw-r--r--clang/lib/Sema/SemaInit.cpp97
4 files changed, 165 insertions, 44 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index dd346176bf0..e2dd64a7036 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -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() {
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index d64228794bd..dc80bd98ec2 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -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,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a5999cc8908..ef2bf91cb79 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -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;
@@ -516,7 +520,19 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
Ctx = Ctx->getParent();
} 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
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 3a053216aef..a0f4e4ac385 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -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,
OpenPOWER on IntegriCloud