diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Expr.cpp | 66 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 44 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 97 |
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, |