| //===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements semantic analysis for initializers. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/ExprCXX.h" |
| #include "clang/AST/ExprObjC.h" |
| #include "clang/AST/TypeLoc.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "clang/Sema/Designator.h" |
| #include "clang/Sema/Initialization.h" |
| #include "clang/Sema/Lookup.h" |
| #include "clang/Sema/SemaInternal.h" |
| #include "llvm/ADT/APInt.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| using namespace clang; |
| |
| //===----------------------------------------------------------------------===// |
| // Sema Initialization Checking |
| //===----------------------------------------------------------------------===// |
| |
| /// \brief Check whether T is compatible with a wide character type (wchar_t, |
| /// char16_t or char32_t). |
| static bool IsWideCharCompatible(QualType T, ASTContext &Context) { |
| if (Context.typesAreCompatible(Context.getWideCharType(), T)) |
| return true; |
| if (Context.getLangOpts().CPlusPlus || Context.getLangOpts().C11) { |
| return Context.typesAreCompatible(Context.Char16Ty, T) || |
| Context.typesAreCompatible(Context.Char32Ty, T); |
| } |
| return false; |
| } |
| |
| enum StringInitFailureKind { |
| SIF_None, |
| SIF_NarrowStringIntoWideChar, |
| SIF_WideStringIntoChar, |
| SIF_IncompatWideStringIntoWideChar, |
| SIF_Other |
| }; |
| |
| /// \brief Check whether the array of type AT can be initialized by the Init |
| /// expression by means of string initialization. Returns SIF_None if so, |
| /// otherwise returns a StringInitFailureKind that describes why the |
| /// initialization would not work. |
| static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, |
| ASTContext &Context) { |
| if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT)) |
| return SIF_Other; |
| |
| // See if this is a string literal or @encode. |
| Init = Init->IgnoreParens(); |
| |
| // Handle @encode, which is a narrow string. |
| if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType()) |
| return SIF_None; |
| |
| // Otherwise we can only handle string literals. |
| StringLiteral *SL = dyn_cast<StringLiteral>(Init); |
| if (!SL) |
| return SIF_Other; |
| |
| const QualType ElemTy = |
| Context.getCanonicalType(AT->getElementType()).getUnqualifiedType(); |
| |
| switch (SL->getKind()) { |
| case StringLiteral::Ascii: |
| case StringLiteral::UTF8: |
| // char array can be initialized with a narrow string. |
| // Only allow char x[] = "foo"; not char x[] = L"foo"; |
| if (ElemTy->isCharType()) |
| return SIF_None; |
| if (IsWideCharCompatible(ElemTy, Context)) |
| return SIF_NarrowStringIntoWideChar; |
| return SIF_Other; |
| // C99 6.7.8p15 (with correction from DR343), or C11 6.7.9p15: |
| // "An array with element type compatible with a qualified or unqualified |
| // version of wchar_t, char16_t, or char32_t may be initialized by a wide |
| // string literal with the corresponding encoding prefix (L, u, or U, |
| // respectively), optionally enclosed in braces. |
| case StringLiteral::UTF16: |
| if (Context.typesAreCompatible(Context.Char16Ty, ElemTy)) |
| return SIF_None; |
| if (ElemTy->isCharType()) |
| return SIF_WideStringIntoChar; |
| if (IsWideCharCompatible(ElemTy, Context)) |
| return SIF_IncompatWideStringIntoWideChar; |
| return SIF_Other; |
| case StringLiteral::UTF32: |
| if (Context.typesAreCompatible(Context.Char32Ty, ElemTy)) |
| return SIF_None; |
| if (ElemTy->isCharType()) |
| return SIF_WideStringIntoChar; |
| if (IsWideCharCompatible(ElemTy, Context)) |
| return SIF_IncompatWideStringIntoWideChar; |
| return SIF_Other; |
| case StringLiteral::Wide: |
| if (Context.typesAreCompatible(Context.getWideCharType(), ElemTy)) |
| return SIF_None; |
| if (ElemTy->isCharType()) |
| return SIF_WideStringIntoChar; |
| if (IsWideCharCompatible(ElemTy, Context)) |
| return SIF_IncompatWideStringIntoWideChar; |
| return SIF_Other; |
| } |
| |
| llvm_unreachable("missed a StringLiteral kind?"); |
| } |
| |
| static StringInitFailureKind IsStringInit(Expr *init, QualType declType, |
| ASTContext &Context) { |
| const ArrayType *arrayType = Context.getAsArrayType(declType); |
| if (!arrayType) |
| return SIF_Other; |
| return IsStringInit(init, arrayType, Context); |
| } |
| |
| /// Update the type of a string literal, including any surrounding parentheses, |
| /// to match the type of the object which it is initializing. |
| static void updateStringLiteralType(Expr *E, QualType Ty) { |
| while (true) { |
| E->setType(Ty); |
| if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E)) |
| break; |
| else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) |
| E = PE->getSubExpr(); |
| else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) |
| E = UO->getSubExpr(); |
| else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) |
| E = GSE->getResultExpr(); |
| else |
| llvm_unreachable("unexpected expr in string literal init"); |
| } |
| } |
| |
| static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, |
| Sema &S) { |
| // Get the length of the string as parsed. |
| auto *ConstantArrayTy = |
| cast<ConstantArrayType>(Str->getType()->getAsArrayTypeUnsafe()); |
| uint64_t StrLength = ConstantArrayTy->getSize().getZExtValue(); |
| |
| if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) { |
| // C99 6.7.8p14. We have an array of character type with unknown size |
| // being initialized to a string literal. |
| llvm::APInt ConstVal(32, StrLength); |
| // Return a new array type (C99 6.7.8p22). |
| DeclT = S.Context.getConstantArrayType(IAT->getElementType(), |
| ConstVal, |
| ArrayType::Normal, 0); |
| updateStringLiteralType(Str, DeclT); |
| return; |
| } |
| |
| const ConstantArrayType *CAT = cast<ConstantArrayType>(AT); |
| |
| // We have an array of character type with known size. However, |
| // the size may be smaller or larger than the string we are initializing. |
| // FIXME: Avoid truncation for 64-bit length strings. |
| if (S.getLangOpts().CPlusPlus) { |
| if (StringLiteral *SL = dyn_cast<StringLiteral>(Str->IgnoreParens())) { |
| // For Pascal strings it's OK to strip off the terminating null character, |
| // so the example below is valid: |
| // |
| // unsigned char a[2] = "\pa"; |
| if (SL->isPascal()) |
| StrLength--; |
| } |
| |
| // [dcl.init.string]p2 |
| if (StrLength > CAT->getSize().getZExtValue()) |
| S.Diag(Str->getLocStart(), |
| diag::err_initializer_string_for_char_array_too_long) |
| << Str->getSourceRange(); |
| } else { |
| // C99 6.7.8p14. |
| if (StrLength-1 > CAT->getSize().getZExtValue()) |
| S.Diag(Str->getLocStart(), |
| diag::ext_initializer_string_for_char_array_too_long) |
| << Str->getSourceRange(); |
| } |
| |
| // Set the type to the actual size that we are initializing. If we have |
| // something like: |
| // char x[1] = "foo"; |
| // then this will set the string literal's type to char[1]. |
| updateStringLiteralType(Str, DeclT); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Semantic checking for initializer lists. |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| |
| /// @brief Semantic checking for initializer lists. |
| /// |
| /// The InitListChecker class contains a set of routines that each |
| /// handle the initialization of a certain kind of entity, e.g., |
| /// arrays, vectors, struct/union types, scalars, etc. The |
| /// InitListChecker itself performs a recursive walk of the subobject |
| /// structure of the type to be initialized, while stepping through |
| /// the initializer list one element at a time. The IList and Index |
| /// parameters to each of the Check* routines contain the active |
| /// (syntactic) initializer list and the index into that initializer |
| /// list that represents the current initializer. Each routine is |
| /// responsible for moving that Index forward as it consumes elements. |
| /// |
| /// Each Check* routine also has a StructuredList/StructuredIndex |
| /// arguments, which contains the current "structured" (semantic) |
| /// initializer list and the index into that initializer list where we |
| /// are copying initializers as we map them over to the semantic |
| /// list. Once we have completed our recursive walk of the subobject |
| /// structure, we will have constructed a full semantic initializer |
| /// list. |
| /// |
| /// C99 designators cause changes in the initializer list traversal, |
| /// because they make the initialization "jump" into a specific |
| /// subobject and then continue the initialization from that |
| /// point. CheckDesignatedInitializer() recursively steps into the |
| /// designated subobject and manages backing out the recursion to |
| /// initialize the subobjects after the one designated. |
| class InitListChecker { |
| Sema &SemaRef; |
| bool hadError; |
| bool VerifyOnly; // no diagnostics, no structure building |
| bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode. |
| llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic; |
| InitListExpr *FullyStructuredList; |
| |
| void CheckImplicitInitList(const InitializedEntity &Entity, |
| InitListExpr *ParentIList, QualType T, |
| unsigned &Index, InitListExpr *StructuredList, |
| unsigned &StructuredIndex); |
| void CheckExplicitInitList(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType &T, |
| InitListExpr *StructuredList, |
| bool TopLevelObject = false); |
| void CheckListElementTypes(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType &DeclType, |
| bool SubobjectIsDesignatorContext, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex, |
| bool TopLevelObject = false); |
| void CheckSubElementType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType ElemType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex); |
| void CheckComplexType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex); |
| void CheckScalarType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex); |
| void CheckReferenceType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex); |
| void CheckVectorType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex); |
| void CheckStructUnionTypes(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, |
| CXXRecordDecl::base_class_range Bases, |
| RecordDecl::field_iterator Field, |
| bool SubobjectIsDesignatorContext, unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex, |
| bool TopLevelObject = false); |
| void CheckArrayType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType &DeclType, |
| llvm::APSInt elementIndex, |
| bool SubobjectIsDesignatorContext, unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex); |
| bool CheckDesignatedInitializer(const InitializedEntity &Entity, |
| InitListExpr *IList, DesignatedInitExpr *DIE, |
| unsigned DesigIdx, |
| QualType &CurrentObjectType, |
| RecordDecl::field_iterator *NextField, |
| llvm::APSInt *NextElementIndex, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex, |
| bool FinishSubobjectInit, |
| bool TopLevelObject); |
| InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, |
| QualType CurrentObjectType, |
| InitListExpr *StructuredList, |
| unsigned StructuredIndex, |
| SourceRange InitRange, |
| bool IsFullyOverwritten = false); |
| void UpdateStructuredListElement(InitListExpr *StructuredList, |
| unsigned &StructuredIndex, |
| Expr *expr); |
| int numArrayElements(QualType DeclType); |
| int numStructUnionElements(QualType DeclType); |
| |
| static ExprResult PerformEmptyInit(Sema &SemaRef, |
| SourceLocation Loc, |
| const InitializedEntity &Entity, |
| bool VerifyOnly, |
| bool TreatUnavailableAsInvalid); |
| |
| // Explanation on the "FillWithNoInit" mode: |
| // |
| // Assume we have the following definitions (Case#1): |
| // struct P { char x[6][6]; } xp = { .x[1] = "bar" }; |
| // struct PP { struct P lp; } l = { .lp = xp, .lp.x[1][2] = 'f' }; |
| // |
| // l.lp.x[1][0..1] should not be filled with implicit initializers because the |
| // "base" initializer "xp" will provide values for them; l.lp.x[1] will be "baf". |
| // |
| // But if we have (Case#2): |
| // struct PP l = { .lp = xp, .lp.x[1] = { [2] = 'f' } }; |
| // |
| // l.lp.x[1][0..1] are implicitly initialized and do not use values from the |
| // "base" initializer; l.lp.x[1] will be "\0\0f\0\0\0". |
| // |
| // To distinguish Case#1 from Case#2, and also to avoid leaving many "holes" |
| // in the InitListExpr, the "holes" in Case#1 are filled not with empty |
| // initializers but with special "NoInitExpr" place holders, which tells the |
| // CodeGen not to generate any initializers for these parts. |
| void FillInEmptyInitForBase(unsigned Init, const CXXBaseSpecifier &Base, |
| const InitializedEntity &ParentEntity, |
| InitListExpr *ILE, bool &RequiresSecondPass, |
| bool FillWithNoInit); |
| void FillInEmptyInitForField(unsigned Init, FieldDecl *Field, |
| const InitializedEntity &ParentEntity, |
| InitListExpr *ILE, bool &RequiresSecondPass, |
| bool FillWithNoInit = false); |
| void FillInEmptyInitializations(const InitializedEntity &Entity, |
| InitListExpr *ILE, bool &RequiresSecondPass, |
| InitListExpr *OuterILE, unsigned OuterIndex, |
| bool FillWithNoInit = false); |
| bool CheckFlexibleArrayInit(const InitializedEntity &Entity, |
| Expr *InitExpr, FieldDecl *Field, |
| bool TopLevelObject); |
| void CheckEmptyInitializable(const InitializedEntity &Entity, |
| SourceLocation Loc); |
| |
| public: |
| InitListChecker(Sema &S, const InitializedEntity &Entity, |
| InitListExpr *IL, QualType &T, bool VerifyOnly, |
| bool TreatUnavailableAsInvalid); |
| bool HadError() { return hadError; } |
| |
| // @brief Retrieves the fully-structured initializer list used for |
| // semantic analysis and code generation. |
| InitListExpr *getFullyStructuredList() const { return FullyStructuredList; } |
| }; |
| |
| } // end anonymous namespace |
| |
| ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, |
| SourceLocation Loc, |
| const InitializedEntity &Entity, |
| bool VerifyOnly, |
| bool TreatUnavailableAsInvalid) { |
| InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, |
| true); |
| MultiExprArg SubInit; |
| Expr *InitExpr; |
| InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc); |
| |
| // C++ [dcl.init.aggr]p7: |
| // If there are fewer initializer-clauses in the list than there are |
| // members in the aggregate, then each member not explicitly initialized |
| // ... |
| bool EmptyInitList = SemaRef.getLangOpts().CPlusPlus11 && |
| Entity.getType()->getBaseElementTypeUnsafe()->isRecordType(); |
| if (EmptyInitList) { |
| // C++1y / DR1070: |
| // shall be initialized [...] from an empty initializer list. |
| // |
| // We apply the resolution of this DR to C++11 but not C++98, since C++98 |
| // does not have useful semantics for initialization from an init list. |
| // We treat this as copy-initialization, because aggregate initialization |
| // always performs copy-initialization on its elements. |
| // |
| // Only do this if we're initializing a class type, to avoid filling in |
| // the initializer list where possible. |
| InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context) |
| InitListExpr(SemaRef.Context, Loc, None, Loc); |
| InitExpr->setType(SemaRef.Context.VoidTy); |
| SubInit = InitExpr; |
| Kind = InitializationKind::CreateCopy(Loc, Loc); |
| } else { |
| // C++03: |
| // shall be value-initialized. |
| } |
| |
| InitializationSequence InitSeq(SemaRef, Entity, Kind, SubInit); |
| // libstdc++4.6 marks the vector default constructor as explicit in |
| // _GLIBCXX_DEBUG mode, so recover using the C++03 logic in that case. |
| // stlport does so too. Look for std::__debug for libstdc++, and for |
| // std:: for stlport. This is effectively a compiler-side implementation of |
| // LWG2193. |
| if (!InitSeq && EmptyInitList && InitSeq.getFailureKind() == |
| InitializationSequence::FK_ExplicitConstructor) { |
| OverloadCandidateSet::iterator Best; |
| OverloadingResult O = |
| InitSeq.getFailedCandidateSet() |
| .BestViableFunction(SemaRef, Kind.getLocation(), Best); |
| (void)O; |
| assert(O == OR_Success && "Inconsistent overload resolution"); |
| CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function); |
| CXXRecordDecl *R = CtorDecl->getParent(); |
| |
| if (CtorDecl->getMinRequiredArguments() == 0 && |
| CtorDecl->isExplicit() && R->getDeclName() && |
| SemaRef.SourceMgr.isInSystemHeader(CtorDecl->getLocation())) { |
| bool IsInStd = false; |
| for (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(R->getDeclContext()); |
| ND && !IsInStd; ND = dyn_cast<NamespaceDecl>(ND->getParent())) { |
| if (SemaRef.getStdNamespace()->InEnclosingNamespaceSetOf(ND)) |
| IsInStd = true; |
| } |
| |
| if (IsInStd && llvm::StringSwitch<bool>(R->getName()) |
| .Cases("basic_string", "deque", "forward_list", true) |
| .Cases("list", "map", "multimap", "multiset", true) |
| .Cases("priority_queue", "queue", "set", "stack", true) |
| .Cases("unordered_map", "unordered_set", "vector", true) |
| .Default(false)) { |
| InitSeq.InitializeFrom( |
| SemaRef, Entity, |
| InitializationKind::CreateValue(Loc, Loc, Loc, true), |
| MultiExprArg(), /*TopLevelOfInitList=*/false, |
| TreatUnavailableAsInvalid); |
| // Emit a warning for this. System header warnings aren't shown |
| // by default, but people working on system headers should see it. |
| if (!VerifyOnly) { |
| SemaRef.Diag(CtorDecl->getLocation(), |
| diag::warn_invalid_initializer_from_system_header); |
| if (Entity.getKind() == InitializedEntity::EK_Member) |
| SemaRef.Diag(Entity.getDecl()->getLocation(), |
| diag::note_used_in_initialization_here); |
| else if (Entity.getKind() == InitializedEntity::EK_ArrayElement) |
| SemaRef.Diag(Loc, diag::note_used_in_initialization_here); |
| } |
| } |
| } |
| } |
| if (!InitSeq) { |
| if (!VerifyOnly) { |
| InitSeq.Diagnose(SemaRef, Entity, Kind, SubInit); |
| if (Entity.getKind() == InitializedEntity::EK_Member) |
| SemaRef.Diag(Entity.getDecl()->getLocation(), |
| diag::note_in_omitted_aggregate_initializer) |
| << /*field*/1 << Entity.getDecl(); |
| else if (Entity.getKind() == InitializedEntity::EK_ArrayElement) { |
| bool IsTrailingArrayNewMember = |
| Entity.getParent() && |
| Entity.getParent()->isVariableLengthArrayNew(); |
| SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer) |
| << (IsTrailingArrayNewMember ? 2 : /*array element*/0) |
| << Entity.getElementIndex(); |
| } |
| } |
| return ExprError(); |
| } |
| |
| return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr)) |
| : InitSeq.Perform(SemaRef, Entity, Kind, SubInit); |
| } |
| |
| void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity, |
| SourceLocation Loc) { |
| assert(VerifyOnly && |
| "CheckEmptyInitializable is only inteded for verification mode."); |
| if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true, |
| TreatUnavailableAsInvalid).isInvalid()) |
| hadError = true; |
| } |
| |
| void InitListChecker::FillInEmptyInitForBase( |
| unsigned Init, const CXXBaseSpecifier &Base, |
| const InitializedEntity &ParentEntity, InitListExpr *ILE, |
| bool &RequiresSecondPass, bool FillWithNoInit) { |
| assert(Init < ILE->getNumInits() && "should have been expanded"); |
| |
| InitializedEntity BaseEntity = InitializedEntity::InitializeBase( |
| SemaRef.Context, &Base, false, &ParentEntity); |
| |
| if (!ILE->getInit(Init)) { |
| ExprResult BaseInit = |
| FillWithNoInit ? new (SemaRef.Context) NoInitExpr(Base.getType()) |
| : PerformEmptyInit(SemaRef, ILE->getLocEnd(), BaseEntity, |
| /*VerifyOnly*/ false, |
| TreatUnavailableAsInvalid); |
| if (BaseInit.isInvalid()) { |
| hadError = true; |
| return; |
| } |
| |
| ILE->setInit(Init, BaseInit.getAs<Expr>()); |
| } else if (InitListExpr *InnerILE = |
| dyn_cast<InitListExpr>(ILE->getInit(Init))) { |
| FillInEmptyInitializations(BaseEntity, InnerILE, RequiresSecondPass, |
| ILE, Init, FillWithNoInit); |
| } else if (DesignatedInitUpdateExpr *InnerDIUE = |
| dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) { |
| FillInEmptyInitializations(BaseEntity, InnerDIUE->getUpdater(), |
| RequiresSecondPass, ILE, Init, |
| /*FillWithNoInit =*/true); |
| } |
| } |
| |
| void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, |
| const InitializedEntity &ParentEntity, |
| InitListExpr *ILE, |
| bool &RequiresSecondPass, |
| bool FillWithNoInit) { |
| SourceLocation Loc = ILE->getLocEnd(); |
| unsigned NumInits = ILE->getNumInits(); |
| InitializedEntity MemberEntity |
| = InitializedEntity::InitializeMember(Field, &ParentEntity); |
| |
| if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) |
| if (!RType->getDecl()->isUnion()) |
| assert(Init < NumInits && "This ILE should have been expanded"); |
| |
| if (Init >= NumInits || !ILE->getInit(Init)) { |
| if (FillWithNoInit) { |
| Expr *Filler = new (SemaRef.Context) NoInitExpr(Field->getType()); |
| if (Init < NumInits) |
| ILE->setInit(Init, Filler); |
| else |
| ILE->updateInit(SemaRef.Context, Init, Filler); |
| return; |
| } |
| // C++1y [dcl.init.aggr]p7: |
| // If there are fewer initializer-clauses in the list than there are |
| // members in the aggregate, then each member not explicitly initialized |
| // shall be initialized from its brace-or-equal-initializer [...] |
| if (Field->hasInClassInitializer()) { |
| ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field); |
| if (DIE.isInvalid()) { |
| hadError = true; |
| return; |
| } |
| if (Init < NumInits) |
| ILE->setInit(Init, DIE.get()); |
| else { |
| ILE->updateInit(SemaRef.Context, Init, DIE.get()); |
| RequiresSecondPass = true; |
| } |
| return; |
| } |
| |
| if (Field->getType()->isReferenceType()) { |
| // C++ [dcl.init.aggr]p9: |
| // If an incomplete or empty initializer-list leaves a |
| // member of reference type uninitialized, the program is |
| // ill-formed. |
| SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) |
| << Field->getType() |
| << ILE->getSyntacticForm()->getSourceRange(); |
| SemaRef.Diag(Field->getLocation(), |
| diag::note_uninit_reference_member); |
| hadError = true; |
| return; |
| } |
| |
| ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity, |
| /*VerifyOnly*/false, |
| TreatUnavailableAsInvalid); |
| if (MemberInit.isInvalid()) { |
| hadError = true; |
| return; |
| } |
| |
| if (hadError) { |
| // Do nothing |
| } else if (Init < NumInits) { |
| ILE->setInit(Init, MemberInit.getAs<Expr>()); |
| } else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) { |
| // Empty initialization requires a constructor call, so |
| // extend the initializer list to include the constructor |
| // call and make a note that we'll need to take another pass |
| // through the initializer list. |
| ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>()); |
| RequiresSecondPass = true; |
| } |
| } else if (InitListExpr *InnerILE |
| = dyn_cast<InitListExpr>(ILE->getInit(Init))) |
| FillInEmptyInitializations(MemberEntity, InnerILE, |
| RequiresSecondPass, ILE, Init, FillWithNoInit); |
| else if (DesignatedInitUpdateExpr *InnerDIUE |
| = dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) |
| FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(), |
| RequiresSecondPass, ILE, Init, |
| /*FillWithNoInit =*/true); |
| } |
| |
| /// Recursively replaces NULL values within the given initializer list |
| /// with expressions that perform value-initialization of the |
| /// appropriate type, and finish off the InitListExpr formation. |
| void |
| InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, |
| InitListExpr *ILE, |
| bool &RequiresSecondPass, |
| InitListExpr *OuterILE, |
| unsigned OuterIndex, |
| bool FillWithNoInit) { |
| assert((ILE->getType() != SemaRef.Context.VoidTy) && |
| "Should not have void type"); |
| |
| // If this is a nested initializer list, we might have changed its contents |
| // (and therefore some of its properties, such as instantiation-dependence) |
| // while filling it in. Inform the outer initializer list so that its state |
| // can be updated to match. |
| // FIXME: We should fully build the inner initializers before constructing |
| // the outer InitListExpr instead of mutating AST nodes after they have |
| // been used as subexpressions of other nodes. |
| struct UpdateOuterILEWithUpdatedInit { |
| InitListExpr *Outer; |
| unsigned OuterIndex; |
| ~UpdateOuterILEWithUpdatedInit() { |
| if (Outer) |
| Outer->setInit(OuterIndex, Outer->getInit(OuterIndex)); |
| } |
| } UpdateOuterRAII = {OuterILE, OuterIndex}; |
| |
| // A transparent ILE is not performing aggregate initialization and should |
| // not be filled in. |
| if (ILE->isTransparent()) |
| return; |
| |
| if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) { |
| const RecordDecl *RDecl = RType->getDecl(); |
| if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) |
| FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), |
| Entity, ILE, RequiresSecondPass, FillWithNoInit); |
| else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) && |
| cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) { |
| for (auto *Field : RDecl->fields()) { |
| if (Field->hasInClassInitializer()) { |
| FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass, |
| FillWithNoInit); |
| break; |
| } |
| } |
| } else { |
| // The fields beyond ILE->getNumInits() are default initialized, so in |
| // order to leave them uninitialized, the ILE is expanded and the extra |
| // fields are then filled with NoInitExpr. |
| unsigned NumElems = numStructUnionElements(ILE->getType()); |
| if (RDecl->hasFlexibleArrayMember()) |
| ++NumElems; |
| if (ILE->getNumInits() < NumElems) |
| ILE->resizeInits(SemaRef.Context, NumElems); |
| |
| unsigned Init = 0; |
| |
| if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RDecl)) { |
| for (auto &Base : CXXRD->bases()) { |
| if (hadError) |
| return; |
| |
| FillInEmptyInitForBase(Init, Base, Entity, ILE, RequiresSecondPass, |
| FillWithNoInit); |
| ++Init; |
| } |
| } |
| |
| for (auto *Field : RDecl->fields()) { |
| if (Field->isUnnamedBitfield()) |
| continue; |
| |
| if (hadError) |
| return; |
| |
| FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass, |
| FillWithNoInit); |
| if (hadError) |
| return; |
| |
| ++Init; |
| |
| // Only look at the first initialization of a union. |
| if (RDecl->isUnion()) |
| break; |
| } |
| } |
| |
| return; |
| } |
| |
| QualType ElementType; |
| |
| InitializedEntity ElementEntity = Entity; |
| unsigned NumInits = ILE->getNumInits(); |
| unsigned NumElements = NumInits; |
| if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) { |
| ElementType = AType->getElementType(); |
| if (const auto *CAType = dyn_cast<ConstantArrayType>(AType)) |
| NumElements = CAType->getSize().getZExtValue(); |
| // For an array new with an unknown bound, ask for one additional element |
| // in order to populate the array filler. |
| if (Entity.isVariableLengthArrayNew()) |
| ++NumElements; |
| ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, |
| 0, Entity); |
| } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) { |
| ElementType = VType->getElementType(); |
| NumElements = VType->getNumElements(); |
| ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, |
| 0, Entity); |
| } else |
| ElementType = ILE->getType(); |
| |
| for (unsigned Init = 0; Init != NumElements; ++Init) { |
| if (hadError) |
| return; |
| |
| if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement || |
| ElementEntity.getKind() == InitializedEntity::EK_VectorElement) |
| ElementEntity.setElementIndex(Init); |
| |
| Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr); |
| if (!InitExpr && Init < NumInits && ILE->hasArrayFiller()) |
| ILE->setInit(Init, ILE->getArrayFiller()); |
| else if (!InitExpr && !ILE->hasArrayFiller()) { |
| Expr *Filler = nullptr; |
| |
| if (FillWithNoInit) |
| Filler = new (SemaRef.Context) NoInitExpr(ElementType); |
| else { |
| ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(), |
| ElementEntity, |
| /*VerifyOnly*/false, |
| TreatUnavailableAsInvalid); |
| if (ElementInit.isInvalid()) { |
| hadError = true; |
| return; |
| } |
| |
| Filler = ElementInit.getAs<Expr>(); |
| } |
| |
| if (hadError) { |
| // Do nothing |
| } else if (Init < NumInits) { |
| // For arrays, just set the expression used for value-initialization |
| // of the "holes" in the array. |
| if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) |
| ILE->setArrayFiller(Filler); |
| else |
| ILE->setInit(Init, Filler); |
| } else { |
| // For arrays, just set the expression used for value-initialization |
| // of the rest of elements and exit. |
| if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) { |
| ILE->setArrayFiller(Filler); |
| return; |
| } |
| |
| if (!isa<ImplicitValueInitExpr>(Filler) && !isa<NoInitExpr>(Filler)) { |
| // Empty initialization requires a constructor call, so |
| // extend the initializer list to include the constructor |
| // call and make a note that we'll need to take another pass |
| // through the initializer list. |
| ILE->updateInit(SemaRef.Context, Init, Filler); |
| RequiresSecondPass = true; |
| } |
| } |
| } else if (InitListExpr *InnerILE |
| = dyn_cast_or_null<InitListExpr>(InitExpr)) |
| FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass, |
| ILE, Init, FillWithNoInit); |
| else if (DesignatedInitUpdateExpr *InnerDIUE |
| = dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr)) |
| FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(), |
| RequiresSecondPass, ILE, Init, |
| /*FillWithNoInit =*/true); |
| } |
| } |
| |
| InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, |
| InitListExpr *IL, QualType &T, |
| bool VerifyOnly, |
| bool TreatUnavailableAsInvalid) |
| : SemaRef(S), VerifyOnly(VerifyOnly), |
| TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) { |
| // FIXME: Check that IL isn't already the semantic form of some other |
| // InitListExpr. If it is, we'd create a broken AST. |
| |
| hadError = false; |
| |
| FullyStructuredList = |
| getStructuredSubobjectInit(IL, 0, T, nullptr, 0, IL->getSourceRange()); |
| CheckExplicitInitList(Entity, IL, T, FullyStructuredList, |
| /*TopLevelObject=*/true); |
| |
| if (!hadError && !VerifyOnly) { |
| bool RequiresSecondPass = false; |
| FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass, |
| /*OuterILE=*/nullptr, /*OuterIndex=*/0); |
| if (RequiresSecondPass && !hadError) |
| FillInEmptyInitializations(Entity, FullyStructuredList, |
| RequiresSecondPass, nullptr, 0); |
| } |
| } |
| |
| int InitListChecker::numArrayElements(QualType DeclType) { |
| // FIXME: use a proper constant |
| int maxElements = 0x7FFFFFFF; |
| if (const ConstantArrayType *CAT = |
| SemaRef.Context.getAsConstantArrayType(DeclType)) { |
| maxElements = static_cast<int>(CAT->getSize().getZExtValue()); |
| } |
| return maxElements; |
| } |
| |
| int InitListChecker::numStructUnionElements(QualType DeclType) { |
| RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl(); |
| int InitializableMembers = 0; |
| if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl)) |
| InitializableMembers += CXXRD->getNumBases(); |
| for (const auto *Field : structDecl->fields()) |
| if (!Field->isUnnamedBitfield()) |
| ++InitializableMembers; |
| |
| if (structDecl->isUnion()) |
| return std::min(InitializableMembers, 1); |
| return InitializableMembers - structDecl->hasFlexibleArrayMember(); |
| } |
| |
| /// Determine whether Entity is an entity for which it is idiomatic to elide |
| /// the braces in aggregate initialization. |
| static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) { |
| // Recursive initialization of the one and only field within an aggregate |
| // class is considered idiomatic. This case arises in particular for |
| // initialization of std::array, where the C++ standard suggests the idiom of |
| // |
| // std::array<T, N> arr = {1, 2, 3}; |
| // |
| // (where std::array is an aggregate struct containing a single array field. |
| |
| // FIXME: Should aggregate initialization of a struct with a single |
| // base class and no members also suppress the warning? |
| if (Entity.getKind() != InitializedEntity::EK_Member || !Entity.getParent()) |
| return false; |
| |
| auto *ParentRD = |
| Entity.getParent()->getType()->castAs<RecordType>()->getDecl(); |
| if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) |
| if (CXXRD->getNumBases()) |
| return false; |
| |
| auto FieldIt = ParentRD->field_begin(); |
| assert(FieldIt != ParentRD->field_end() && |
| "no fields but have initializer for member?"); |
| return ++FieldIt == ParentRD->field_end(); |
| } |
| |
| /// Check whether the range of the initializer \p ParentIList from element |
| /// \p Index onwards can be used to initialize an object of type \p T. Update |
| /// \p Index to indicate how many elements of the list were consumed. |
| /// |
| /// This also fills in \p StructuredList, from element \p StructuredIndex |
| /// onwards, with the fully-braced, desugared form of the initialization. |
| void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, |
| InitListExpr *ParentIList, |
| QualType T, unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex) { |
| int maxElements = 0; |
| |
| if (T->isArrayType()) |
| maxElements = numArrayElements(T); |
| else if (T->isRecordType()) |
| maxElements = numStructUnionElements(T); |
| else if (T->isVectorType()) |
| maxElements = T->getAs<VectorType>()->getNumElements(); |
| else |
| llvm_unreachable("CheckImplicitInitList(): Illegal type"); |
| |
| if (maxElements == 0) { |
| if (!VerifyOnly) |
| SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(), |
| diag::err_implicit_empty_initializer); |
| ++Index; |
| hadError = true; |
| return; |
| } |
| |
| // Build a structured initializer list corresponding to this subobject. |
| InitListExpr *StructuredSubobjectInitList |
| = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList, |
| StructuredIndex, |
| SourceRange(ParentIList->getInit(Index)->getLocStart(), |
| ParentIList->getSourceRange().getEnd())); |
| unsigned StructuredSubobjectInitIndex = 0; |
| |
| // Check the element types and build the structural subobject. |
| unsigned StartIndex = Index; |
| CheckListElementTypes(Entity, ParentIList, T, |
| /*SubobjectIsDesignatorContext=*/false, Index, |
| StructuredSubobjectInitList, |
| StructuredSubobjectInitIndex); |
| |
| if (!VerifyOnly) { |
| StructuredSubobjectInitList->setType(T); |
| |
| unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1); |
| // Update the structured sub-object initializer so that it's ending |
| // range corresponds with the end of the last initializer it used. |
| if (EndIndex < ParentIList->getNumInits() && |
| ParentIList->getInit(EndIndex)) { |
| SourceLocation EndLoc |
| = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); |
| StructuredSubobjectInitList->setRBraceLoc(EndLoc); |
| } |
| |
| // Complain about missing braces. |
| if ((T->isArrayType() || T->isRecordType()) && |
| !ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && |
| !isIdiomaticBraceElisionEntity(Entity)) { |
| SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), |
| diag::warn_missing_braces) |
| << StructuredSubobjectInitList->getSourceRange() |
| << FixItHint::CreateInsertion( |
| StructuredSubobjectInitList->getLocStart(), "{") |
| << FixItHint::CreateInsertion( |
| SemaRef.getLocForEndOfToken( |
| StructuredSubobjectInitList->getLocEnd()), |
| "}"); |
| } |
| } |
| } |
| |
| /// Warn that \p Entity was of scalar type and was initialized by a |
| /// single-element braced initializer list. |
| static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, |
| SourceRange Braces) { |
| // Don't warn during template instantiation. If the initialization was |
| // non-dependent, we warned during the initial parse; otherwise, the |
| // type might not be scalar in some uses of the template. |
| if (S.inTemplateInstantiation()) |
| return; |
| |
| unsigned DiagID = 0; |
| |
| switch (Entity.getKind()) { |
| case InitializedEntity::EK_VectorElement: |
| case InitializedEntity::EK_ComplexElement: |
| case InitializedEntity::EK_ArrayElement: |
| case InitializedEntity::EK_Parameter: |
| case InitializedEntity::EK_Parameter_CF_Audited: |
| case InitializedEntity::EK_Result: |
| // Extra braces here are suspicious. |
| DiagID = diag::warn_braces_around_scalar_init; |
| break; |
| |
| case InitializedEntity::EK_Member: |
| // Warn on aggregate initialization but not on ctor init list or |
| // default member initializer. |
| if (Entity.getParent()) |
| DiagID = diag::warn_braces_around_scalar_init; |
| break; |
| |
| case InitializedEntity::EK_Variable: |
| case InitializedEntity::EK_LambdaCapture: |
| // No warning, might be direct-list-initialization. |
| // FIXME: Should we warn for copy-list-initialization in these cases? |
| break; |
| |
| case InitializedEntity::EK_New: |
| case InitializedEntity::EK_Temporary: |
| case InitializedEntity::EK_CompoundLiteralInit: |
| // No warning, braces are part of the syntax of the underlying construct. |
| break; |
| |
| case InitializedEntity::EK_RelatedResult: |
| // No warning, we already warned when initializing the result. |
| break; |
| |
| case InitializedEntity::EK_Exception: |
| case InitializedEntity::EK_Base: |
| case InitializedEntity::EK_Delegating: |
| case InitializedEntity::EK_BlockElement: |
| case InitializedEntity::EK_LambdaToBlockConversionBlockElement: |
| case InitializedEntity::EK_Binding: |
| llvm_unreachable("unexpected braced scalar init"); |
| } |
| |
| if (DiagID) { |
| S.Diag(Braces.getBegin(), DiagID) |
| << Braces |
| << FixItHint::CreateRemoval(Braces.getBegin()) |
| << FixItHint::CreateRemoval(Braces.getEnd()); |
| } |
| } |
| |
| /// Check whether the initializer \p IList (that was written with explicit |
| /// braces) can be used to initialize an object of type \p T. |
| /// |
| /// This also fills in \p StructuredList with the fully-braced, desugared |
| /// form of the initialization. |
| void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType &T, |
| InitListExpr *StructuredList, |
| bool TopLevelObject) { |
| if (!VerifyOnly) { |
| SyntacticToSemantic[IList] = StructuredList; |
| StructuredList->setSyntacticForm(IList); |
| } |
| |
| unsigned Index = 0, StructuredIndex = 0; |
| CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, |
| Index, StructuredList, StructuredIndex, TopLevelObject); |
| if (!VerifyOnly) { |
| QualType ExprTy = T; |
| if (!ExprTy->isArrayType()) |
| ExprTy = ExprTy.getNonLValueExprType(SemaRef.Context); |
| IList->setType(ExprTy); |
| StructuredList->setType(ExprTy); |
| } |
| if (hadError) |
| return; |
| |
| if (Index < IList->getNumInits()) { |
| // We have leftover initializers |
| if (VerifyOnly) { |
| if (SemaRef.getLangOpts().CPlusPlus || |
| (SemaRef.getLangOpts().OpenCL && |
| IList->getType()->isVectorType())) { |
| hadError = true; |
| } |
| return; |
| } |
| |
| if (StructuredIndex == 1 && |
| IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) == |
| SIF_None) { |
| unsigned DK = diag::ext_excess_initializers_in_char_array_initializer; |
| if (SemaRef.getLangOpts().CPlusPlus) { |
| DK = diag::err_excess_initializers_in_char_array_initializer; |
| hadError = true; |
| } |
| // Special-case |
| SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK) |
| << IList->getInit(Index)->getSourceRange(); |
| } else if (!T->isIncompleteType()) { |
| // Don't complain for incomplete types, since we'll get an error |
| // elsewhere |
| QualType CurrentObjectType = StructuredList->getType(); |
| int initKind = |
| CurrentObjectType->isArrayType()? 0 : |
| CurrentObjectType->isVectorType()? 1 : |
| CurrentObjectType->isScalarType()? 2 : |
| CurrentObjectType->isUnionType()? 3 : |
| 4; |
| |
| unsigned DK = diag::ext_excess_initializers; |
| if (SemaRef.getLangOpts().CPlusPlus) { |
| DK = diag::err_excess_initializers; |
| hadError = true; |
| } |
| if (SemaRef.getLangOpts().OpenCL && initKind == 1) { |
| DK = diag::err_excess_initializers; |
| hadError = true; |
| } |
| |
| SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK) |
| << initKind << IList->getInit(Index)->getSourceRange(); |
| } |
| } |
| |
| if (!VerifyOnly && T->isScalarType() && |
| IList->getNumInits() == 1 && !isa<InitListExpr>(IList->getInit(0))) |
| warnBracedScalarInit(SemaRef, Entity, IList->getSourceRange()); |
| } |
| |
| void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, |
| InitListExpr *IList, |
| QualType &DeclType, |
| bool SubobjectIsDesignatorContext, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex, |
| bool TopLevelObject) { |
| if (DeclType->isAnyComplexType() && SubobjectIsDesignatorContext) { |
| // Explicitly braced initializer for complex type can be real+imaginary |
| // parts. |
| CheckComplexType(Entity, IList, DeclType, Index, |
| StructuredList, StructuredIndex); |
| } else if (DeclType->isScalarType()) { |
| CheckScalarType(Entity, IList, DeclType, Index, |
| StructuredList, StructuredIndex); |
| } else if (DeclType->isVectorType()) { |
| CheckVectorType(Entity, IList, DeclType, Index, |
| StructuredList, StructuredIndex); |
| } else if (DeclType->isRecordType()) { |
| assert(DeclType->isAggregateType() && |
| "non-aggregate records should be handed in CheckSubElementType"); |
| RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); |
| auto Bases = |
| CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(), |
| CXXRecordDecl::base_class_iterator()); |
| if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) |
| Bases = CXXRD->bases(); |
| CheckStructUnionTypes(Entity, IList, DeclType, Bases, RD->field_begin(), |
| SubobjectIsDesignatorContext, Index, StructuredList, |
| StructuredIndex, TopLevelObject); |
| } else if (DeclType->isArrayType()) { |
| llvm::APSInt Zero( |
| SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()), |
| false); |
| CheckArrayType(Entity, IList, DeclType, Zero, |
| SubobjectIsDesignatorContext, Index, |
| StructuredList, StructuredIndex); |
| } else if (DeclType->isVoidType() || DeclType->isFunctionType()) { |
| // This type is invalid, issue a diagnostic. |
| ++Index; |
| if (!VerifyOnly) |
| SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) |
| << DeclType; |
| hadError = true; |
| } else if (DeclType->isReferenceType()) { |
| CheckReferenceType(Entity, IList, DeclType, Index, |
| StructuredList, StructuredIndex); |
| } else if (DeclType->isObjCObjectType()) { |
| if (!VerifyOnly) |
| SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) |
| << DeclType; |
| hadError = true; |
| } else { |
| if (!VerifyOnly) |
| SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) |
| << DeclType; |
| hadError = true; |
| } |
| } |
| |
| void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, |
| InitListExpr *IList, |
| QualType ElemType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex) { |
| Expr *expr = IList->getInit(Index); |
| |
| if (ElemType->isReferenceType()) |
| return CheckReferenceType(Entity, IList, ElemType, Index, |
| StructuredList, StructuredIndex); |
| |
| if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) { |
| if (SubInitList->getNumInits() == 1 && |
| IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) == |
| SIF_None) { |
| expr = SubInitList->getInit(0); |
| } else if (!SemaRef.getLangOpts().CPlusPlus) { |
| InitListExpr *InnerStructuredList |
| = getStructuredSubobjectInit(IList, Index, ElemType, |
| StructuredList, StructuredIndex, |
| SubInitList->getSourceRange(), true); |
| CheckExplicitInitList(Entity, SubInitList, ElemType, |
| InnerStructuredList); |
| |
| if (!hadError && !VerifyOnly) { |
| bool RequiresSecondPass = false; |
| FillInEmptyInitializations(Entity, InnerStructuredList, |
| RequiresSecondPass, StructuredList, |
| StructuredIndex); |
| if (RequiresSecondPass && !hadError) |
| FillInEmptyInitializations(Entity, InnerStructuredList, |
| RequiresSecondPass, StructuredList, |
| StructuredIndex); |
| } |
| ++StructuredIndex; |
| ++Index; |
| return; |
| } |
| // C++ initialization is handled later. |
| } else if (isa<ImplicitValueInitExpr>(expr)) { |
| // This happens during template instantiation when we see an InitListExpr |
| // that we've already checked once. |
| assert(SemaRef.Context.hasSameType(expr->getType(), ElemType) && |
| "found implicit initialization for the wrong type"); |
| if (!VerifyOnly) |
| UpdateStructuredListElement(StructuredList, StructuredIndex, expr); |
| ++Index; |
| return; |
| } |
| |
| if (SemaRef.getLangOpts().CPlusPlus) { |
| // C++ [dcl.init.aggr]p2: |
| // Each member is copy-initialized from the corresponding |
| // initializer-clause. |
| |
| // FIXME: Better EqualLoc? |
| InitializationKind Kind = |
| InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation()); |
| InitializationSequence Seq(SemaRef, Entity, Kind, expr, |
| /*TopLevelOfInitList*/ true); |
| |
| // C++14 [dcl.init.aggr]p13: |
| // If the assignment-expression can initialize a member, the member is |
| // initialized. Otherwise [...] brace elision is assumed |
| // |
| // Brace elision is never performed if the element is not an |
| // assignment-expression. |
| if (Seq || isa<InitListExpr>(expr)) { |
| if (!VerifyOnly) { |
| ExprResult Result = |
| Seq.Perform(SemaRef, Entity, Kind, expr); |
| if (Result.isInvalid()) |
| hadError = true; |
| |
| UpdateStructuredListElement(StructuredList, StructuredIndex, |
| Result.getAs<Expr>()); |
| } else if (!Seq) |
| hadError = true; |
| ++Index; |
| return; |
| } |
| |
| // Fall through for subaggregate initialization |
| } else if (ElemType->isScalarType() || ElemType->isAtomicType()) { |
| // FIXME: Need to handle atomic aggregate types with implicit init lists. |
| return CheckScalarType(Entity, IList, ElemType, Index, |
| StructuredList, StructuredIndex); |
| } else if (const ArrayType *arrayType = |
| SemaRef.Context.getAsArrayType(ElemType)) { |
| // arrayType can be incomplete if we're initializing a flexible |
| // array member. There's nothing we can do with the completed |
| // type here, though. |
| |
| if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) { |
| if (!VerifyOnly) { |
| CheckStringInit(expr, ElemType, arrayType, SemaRef); |
| UpdateStructuredListElement(StructuredList, StructuredIndex, expr); |
| } |
| ++Index; |
| return; |
| } |
| |
| // Fall through for subaggregate initialization. |
| |
| } else { |
| assert((ElemType->isRecordType() || ElemType->isVectorType() || |
| ElemType->isOpenCLSpecificType()) && "Unexpected type"); |
| |
| // C99 6.7.8p13: |
| // |
| // The initializer for a structure or union object that has |
| // automatic storage duration shall be either an initializer |
| // list as described below, or a single expression that has |
| // compatible structure or union type. In the latter case, the |
| // initial value of the object, including unnamed members, is |
| // that of the expression. |
| ExprResult ExprRes = expr; |
| if (SemaRef.CheckSingleAssignmentConstraints( |
| ElemType, ExprRes, !VerifyOnly) != Sema::Incompatible) { |
| if (ExprRes.isInvalid()) |
| hadError = true; |
| else { |
| ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.get()); |
| if (ExprRes.isInvalid()) |
| hadError = true; |
| } |
| UpdateStructuredListElement(StructuredList, StructuredIndex, |
| ExprRes.getAs<Expr>()); |
| ++Index; |
| return; |
| } |
| ExprRes.get(); |
| // Fall through for subaggregate initialization |
| } |
| |
| // C++ [dcl.init.aggr]p12: |
| // |
| // [...] Otherwise, if the member is itself a non-empty |
| // subaggregate, brace elision is assumed and the initializer is |
| // considered for the initialization of the first member of |
| // the subaggregate. |
| // OpenCL vector initializer is handled elsewhere. |
| if ((!SemaRef.getLangOpts().OpenCL && ElemType->isVectorType()) || |
| ElemType->isAggregateType()) { |
| CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList, |
| StructuredIndex); |
| ++StructuredIndex; |
| } else { |
| if (!VerifyOnly) { |
| // We cannot initialize this element, so let |
| // PerformCopyInitialization produce the appropriate diagnostic. |
| SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr, |
| /*TopLevelOfInitList=*/true); |
| } |
| hadError = true; |
| ++Index; |
| ++StructuredIndex; |
| } |
| } |
| |
| void InitListChecker::CheckComplexType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex) { |
| assert(Index == 0 && "Index in explicit init list must be zero"); |
| |
| // As an extension, clang supports complex initializers, which initialize |
| // a complex number component-wise. When an explicit initializer list for |
| // a complex number contains two two initializers, this extension kicks in: |
| // it exepcts the initializer list to contain two elements convertible to |
| // the element type of the complex type. The first element initializes |
| // the real part, and the second element intitializes the imaginary part. |
| |
| if (IList->getNumInits() != 2) |
| return CheckScalarType(Entity, IList, DeclType, Index, StructuredList, |
| StructuredIndex); |
| |
| // This is an extension in C. (The builtin _Complex type does not exist |
| // in the C++ standard.) |
| if (!SemaRef.getLangOpts().CPlusPlus && !VerifyOnly) |
| SemaRef.Diag(IList->getLocStart(), diag::ext_complex_component_init) |
| << IList->getSourceRange(); |
| |
| // Initialize the complex number. |
| QualType elementType = DeclType->getAs<ComplexType>()->getElementType(); |
| InitializedEntity ElementEntity = |
| InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); |
| |
| for (unsigned i = 0; i < 2; ++i) { |
| ElementEntity.setElementIndex(Index); |
| CheckSubElementType(ElementEntity, IList, elementType, Index, |
| StructuredList, StructuredIndex); |
| } |
| } |
| |
| void InitListChecker::CheckScalarType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex) { |
| if (Index >= IList->getNumInits()) { |
| if (!VerifyOnly) |
| SemaRef.Diag(IList->getLocStart(), |
| SemaRef.getLangOpts().CPlusPlus11 ? |
| diag::warn_cxx98_compat_empty_scalar_initializer : |
| diag::err_empty_scalar_initializer) |
| << IList->getSourceRange(); |
| hadError = !SemaRef.getLangOpts().CPlusPlus11; |
| ++Index; |
| ++StructuredIndex; |
| return; |
| } |
| |
| Expr *expr = IList->getInit(Index); |
| if (InitListExpr *SubIList = dyn_cast<InitListExpr>(expr)) { |
| // FIXME: This is invalid, and accepting it causes overload resolution |
| // to pick the wrong overload in some corner cases. |
| if (!VerifyOnly) |
| SemaRef.Diag(SubIList->getLocStart(), |
| diag::ext_many_braces_around_scalar_init) |
| << SubIList->getSourceRange(); |
| |
| CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, |
| StructuredIndex); |
| return; |
| } else if (isa<DesignatedInitExpr>(expr)) { |
| if (!VerifyOnly) |
| SemaRef.Diag(expr->getLocStart(), |
| diag::err_designator_for_scalar_init) |
| << DeclType << expr->getSourceRange(); |
| hadError = true; |
| ++Index; |
| ++StructuredIndex; |
| return; |
| } |
| |
| if (VerifyOnly) { |
| if (!SemaRef.CanPerformCopyInitialization(Entity,expr)) |
| hadError = true; |
| ++Index; |
| return; |
| } |
| |
| ExprResult Result = |
| SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), expr, |
| /*TopLevelOfInitList=*/true); |
| |
| Expr *ResultExpr = nullptr; |
| |
| if (Result.isInvalid()) |
| hadError = true; // types weren't compatible. |
| else { |
| ResultExpr = Result.getAs<Expr>(); |
| |
| if (ResultExpr != expr) { |
| // The type was promoted, update initializer list. |
| IList->setInit(Index, ResultExpr); |
| } |
| } |
| if (hadError) |
| ++StructuredIndex; |
| else |
| UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); |
| ++Index; |
| } |
| |
| void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex) { |
| if (Index >= IList->getNumInits()) { |
| // FIXME: It would be wonderful if we could point at the actual member. In |
| // general, it would be useful to pass location information down the stack, |
| // so that we know the location (or decl) of the "current object" being |
| // initialized. |
| if (!VerifyOnly) |
| SemaRef.Diag(IList->getLocStart(), |
| diag::err_init_reference_member_uninitialized) |
| << DeclType |
| << IList->getSourceRange(); |
| hadError = true; |
| ++Index; |
| ++StructuredIndex; |
| return; |
| } |
| |
| Expr *expr = IList->getInit(Index); |
| if (isa<InitListExpr>(expr) && !SemaRef.getLangOpts().CPlusPlus11) { |
| if (!VerifyOnly) |
| SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) |
| << DeclType << IList->getSourceRange(); |
| hadError = true; |
| ++Index; |
| ++StructuredIndex; |
| return; |
| } |
| |
| if (VerifyOnly) { |
| if (!SemaRef.CanPerformCopyInitialization(Entity,expr)) |
| hadError = true; |
| ++Index; |
| return; |
| } |
| |
| ExprResult Result = |
| SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), expr, |
| /*TopLevelOfInitList=*/true); |
| |
| if (Result.isInvalid()) |
| hadError = true; |
| |
| expr = Result.getAs<Expr>(); |
| IList->setInit(Index, expr); |
| |
| if (hadError) |
| ++StructuredIndex; |
| else |
| UpdateStructuredListElement(StructuredList, StructuredIndex, expr); |
| ++Index; |
| } |
| |
| void InitListChecker::CheckVectorType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType DeclType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex) { |
| const VectorType *VT = DeclType->getAs<VectorType>(); |
| unsigned maxElements = VT->getNumElements(); |
| unsigned numEltsInit = 0; |
| QualType elementType = VT->getElementType(); |
| |
| if (Index >= IList->getNumInits()) { |
| // Make sure the element type can be value-initialized. |
| if (VerifyOnly) |
| CheckEmptyInitializable( |
| InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity), |
| IList->getLocEnd()); |
| return; |
| } |
| |
| if (!SemaRef.getLangOpts().OpenCL) { |
| // If the initializing element is a vector, try to copy-initialize |
| // instead of breaking it apart (which is doomed to failure anyway). |
| Expr *Init = IList->getInit(Index); |
| if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) { |
| if (VerifyOnly) { |
| if (!SemaRef.CanPerformCopyInitialization(Entity, Init)) |
| hadError = true; |
| ++Index; |
| return; |
| } |
| |
| ExprResult Result = |
| SemaRef.PerformCopyInitialization(Entity, Init->getLocStart(), Init, |
| /*TopLevelOfInitList=*/true); |
| |
| Expr *ResultExpr = nullptr; |
| if (Result.isInvalid()) |
| hadError = true; // types weren't compatible. |
| else { |
| ResultExpr = Result.getAs<Expr>(); |
| |
| if (ResultExpr != Init) { |
| // The type was promoted, update initializer list. |
| IList->setInit(Index, ResultExpr); |
| } |
| } |
| if (hadError) |
| ++StructuredIndex; |
| else |
| UpdateStructuredListElement(StructuredList, StructuredIndex, |
| ResultExpr); |
| ++Index; |
| return; |
| } |
| |
| InitializedEntity ElementEntity = |
| InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); |
| |
| for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) { |
| // Don't attempt to go past the end of the init list |
| if (Index >= IList->getNumInits()) { |
| if (VerifyOnly) |
| CheckEmptyInitializable(ElementEntity, IList->getLocEnd()); |
| break; |
| } |
| |
| ElementEntity.setElementIndex(Index); |
| CheckSubElementType(ElementEntity, IList, elementType, Index, |
| StructuredList, StructuredIndex); |
| } |
| |
| if (VerifyOnly) |
| return; |
| |
| bool isBigEndian = SemaRef.Context.getTargetInfo().isBigEndian(); |
| const VectorType *T = Entity.getType()->getAs<VectorType>(); |
| if (isBigEndian && (T->getVectorKind() == VectorType::NeonVector || |
| T->getVectorKind() == VectorType::NeonPolyVector)) { |
| // The ability to use vector initializer lists is a GNU vector extension |
| // and is unrelated to the NEON intrinsics in arm_neon.h. On little |
| // endian machines it works fine, however on big endian machines it |
| // exhibits surprising behaviour: |
| // |
| // uint32x2_t x = {42, 64}; |
| // return vget_lane_u32(x, 0); // Will return 64. |
| // |
| // Because of this, explicitly call out that it is non-portable. |
| // |
| SemaRef.Diag(IList->getLocStart(), |
| diag::warn_neon_vector_initializer_non_portable); |
| |
| const char *typeCode; |
| unsigned typeSize = SemaRef.Context.getTypeSize(elementType); |
| |
| if (elementType->isFloatingType()) |
| typeCode = "f"; |
| else if (elementType->isSignedIntegerType()) |
| typeCode = "s"; |
| else if (elementType->isUnsignedIntegerType()) |
| typeCode = "u"; |
| else |
| llvm_unreachable("Invalid element type!"); |
| |
| SemaRef.Diag(IList->getLocStart(), |
| SemaRef.Context.getTypeSize(VT) > 64 ? |
| diag::note_neon_vector_initializer_non_portable_q : |
| diag::note_neon_vector_initializer_non_portable) |
| << typeCode << typeSize; |
| } |
| |
| return; |
| } |
| |
| InitializedEntity ElementEntity = |
| InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); |
| |
| // OpenCL initializers allows vectors to be constructed from vectors. |
| for (unsigned i = 0; i < maxElements; ++i) { |
| // Don't attempt to go past the end of the init list |
| if (Index >= IList->getNumInits()) |
| break; |
| |
| ElementEntity.setElementIndex(Index); |
| |
| QualType IType = IList->getInit(Index)->getType(); |
| if (!IType->isVectorType()) { |
| CheckSubElementType(ElementEntity, IList, elementType, Index, |
| StructuredList, StructuredIndex); |
| ++numEltsInit; |
| } else { |
| QualType VecType; |
| const VectorType *IVT = IType->getAs<VectorType>(); |
| unsigned numIElts = IVT->getNumElements(); |
| |
| if (IType->isExtVectorType()) |
| VecType = SemaRef.Context.getExtVectorType(elementType, numIElts); |
| else |
| VecType = SemaRef.Context.getVectorType(elementType, numIElts, |
| IVT->getVectorKind()); |
| CheckSubElementType(ElementEntity, IList, VecType, Index, |
| StructuredList, StructuredIndex); |
| numEltsInit += numIElts; |
| } |
| } |
| |
| // OpenCL requires all elements to be initialized. |
| if (numEltsInit != maxElements) { |
| if (!VerifyOnly) |
| SemaRef.Diag(IList->getLocStart(), |
| diag::err_vector_incorrect_num_initializers) |
| << (numEltsInit < maxElements) << maxElements << numEltsInit; |
| hadError = true; |
| } |
| } |
| |
| void InitListChecker::CheckArrayType(const InitializedEntity &Entity, |
| InitListExpr *IList, QualType &DeclType, |
| llvm::APSInt elementIndex, |
| bool SubobjectIsDesignatorContext, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex) { |
| const ArrayType *arrayType = SemaRef.Context.getAsArrayType(DeclType); |
| |
| // Check for the special-case of initializing an array with a string. |
| if (Index < IList->getNumInits()) { |
| if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) == |
| SIF_None) { |
| // 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. |
| if (!VerifyOnly) { |
| CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef); |
| UpdateStructuredListElement(StructuredList, StructuredIndex, |
| IList->getInit(Index)); |
| StructuredList->resizeInits(SemaRef.Context, StructuredIndex); |
| } |
| ++Index; |
| return; |
| } |
| } |
| if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(arrayType)) { |
| // Check for VLAs; in standard C it would be possible to check this |
| // earlier, but I don't know where clang accepts VLAs (gcc accepts |
| // them in all sorts of strange places). |
| if (!VerifyOnly) |
| SemaRef.Diag(VAT->getSizeExpr()->getLocStart(), |
| 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()); |
| bool maxElementsKnown = false; |
| if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(arrayType)) { |
| maxElements = CAT->getSize(); |
| elementIndex = elementIndex.extOrTrunc(maxElements.getBitWidth()); |
| elementIndex.setIsUnsigned(maxElements.isUnsigned()); |
| maxElementsKnown = true; |
| } |
| |
| QualType elementType = arrayType->getElementType(); |
| while (Index < IList->getNumInits()) { |
| Expr *Init = IList->getInit(Index); |
| if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) { |
| // If we're not the subobject that matches up with the '{' for |
| // the designator, we shouldn't be handling the |
| // designator. Return immediately. |
| if (!SubobjectIsDesignatorContext) |
| return; |
| |
| // Handle this designated initializer. elementIndex will be |
| // updated to be the next array element we'll initialize. |
| if (CheckDesignatedInitializer(Entity, IList, DIE, 0, |
| DeclType, nullptr, &elementIndex, Index, |
| StructuredList, StructuredIndex, true, |
| false)) { |
| hadError = true; |
| continue; |
| } |
| |
| if (elementIndex.getBitWidth() > maxElements.getBitWidth()) |
| maxElements = maxElements.extend(elementIndex.getBitWidth()); |
| else if (elementIndex.getBitWidth() < maxElements.getBitWidth()) |
| elementIndex = elementIndex.extend(maxElements.getBitWidth()); |
| elementIndex.setIsUnsigned(maxElements.isUnsigned()); |
| |
| // If the array is of incomplete type, keep track of the number of |
| // elements in the initializer. |
| if (!maxElementsKnown && elementIndex > maxElements) |
| maxElements = elementIndex; |
| |
| continue; |
| } |
| |
| // If we know the maximum number of elements, and we've already |
| // hit it, stop consuming elements in the initializer list. |
| if (maxElementsKnown && elementIndex == maxElements) |
| break; |
| |
| InitializedEntity ElementEntity = |
| InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex, |
| Entity); |
| // Check this element. |
| CheckSubElementType(ElementEntity, IList, elementType, Index, |
| StructuredList, StructuredIndex); |
| ++elementIndex; |
| |
| // If the array is of incomplete type, keep track of the number of |
| // elements in the initializer. |
| if (!maxElementsKnown && elementIndex > maxElements) |
| maxElements = elementIndex; |
| } |
| if (!hadError && DeclType->isIncompleteArrayType() && !VerifyOnly) { |
| // If this is an incomplete array type, the actual type needs to |
| // be calculated here. |
| llvm::APSInt Zero(maxElements.getBitWidth(), maxElements.isUnsigned()); |
| if (maxElements == Zero && !Entity.isVariableLengthArrayNew()) { |
| // Sizing an array implicitly to zero is not allowed by ISO C, |
| // but is supported by GNU. |
| SemaRef.Diag(IList->getLocStart(), |
| diag::ext_typecheck_zero_array_size); |
| } |
| |
| DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements, |
| ArrayType::Normal, 0); |
| } |
| if (!hadError && VerifyOnly) { |
| // If there are any members of the array that get value-initialized, check |
| // that is possible. That happens if we know the bound and don't have |
| // enough elements, or if we're performing an array new with an unknown |
| // bound. |
| // FIXME: This needs to detect holes left by designated initializers too. |
| if ((maxElementsKnown && elementIndex < maxElements) || |
| Entity.isVariableLengthArrayNew()) |
| CheckEmptyInitializable(InitializedEntity::InitializeElement( |
| SemaRef.Context, 0, Entity), |
| IList->getLocEnd()); |
| } |
| } |
| |
| bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity, |
| Expr *InitExpr, |
| FieldDecl *Field, |
| bool TopLevelObject) { |
| // Handle GNU flexible array initializers. |
| unsigned FlexArrayDiag; |
| if (isa<InitListExpr>(InitExpr) && |
| cast<InitListExpr>(InitExpr)->getNumInits() == 0) { |
| // Empty flexible array init always allowed as an extension |
| FlexArrayDiag = diag::ext_flexible_array_init; |
| } else if (SemaRef.getLangOpts().CPlusPlus) { |
| // Disallow flexible array init in C++; it is not required for gcc |
| // compatibility, and it needs work to IRGen correctly in general. |
| FlexArrayDiag = diag::err_flexible_array_init; |
| } else if (!TopLevelObject) { |
| // Disallow flexible array init on non-top-level object |
| FlexArrayDiag = diag::err_flexible_array_init; |
| } else if (Entity.getKind() != InitializedEntity::EK_Variable) { |
| // Disallow flexible array init on anything which is not a variable. |
| FlexArrayDiag = diag::err_flexible_array_init; |
| } else if (cast<VarDecl>(Entity.getDecl())->hasLocalStorage()) { |
| // Disallow flexible array init on local variables. |
| FlexArrayDiag = diag::err_flexible_array_init; |
| } else { |
| // Allow other cases. |
| FlexArrayDiag = diag::ext_flexible_array_init; |
| } |
| |
| if (!VerifyOnly) { |
| SemaRef.Diag(InitExpr->getLocStart(), |
| FlexArrayDiag) |
| << InitExpr->getLocStart(); |
| SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) |
| << Field; |
| } |
| |
| return FlexArrayDiag != diag::ext_flexible_array_init; |
| } |
| |
| void InitListChecker::CheckStructUnionTypes( |
| const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, |
| CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field, |
| bool SubobjectIsDesignatorContext, unsigned &Index, |
| InitListExpr *StructuredList, unsigned &StructuredIndex, |
| bool TopLevelObject) { |
| RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl(); |
| |
| // If the record is invalid, some of it's members are invalid. To avoid |
| // confusion, we forgo checking the intializer for the entire record. |
| if (structDecl->isInvalidDecl()) { |
| // Assume it was supposed to consume a single initializer. |
| ++Index; |
| hadError = true; |
| return; |
| } |
| |
| if (DeclType->isUnionType() && IList->getNumInits() == 0) { |
| RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); |
| |
| // If there's a default initializer, use it. |
| if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) { |
| if (VerifyOnly) |
| return; |
| for (RecordDecl::field_iterator FieldEnd = RD->field_end(); |
| Field != FieldEnd; ++Field) { |
| if (Field->hasInClassInitializer()) { |
| StructuredList->setInitializedFieldInUnion(*Field); |
| // FIXME: Actually build a CXXDefaultInitExpr? |
| return; |
| } |
| } |
| } |
| |
| // Value-initialize the first member of the union that isn't an unnamed |
| // bitfield. |
| for (RecordDecl::field_iterator FieldEnd = RD->field_end(); |
| Field != FieldEnd; ++Field) { |
| if (!Field->isUnnamedBitfield()) { |
| if (VerifyOnly) |
| CheckEmptyInitializable( |
| InitializedEntity::InitializeMember(*Field, &Entity), |
| IList->getLocEnd()); |
| else |
| StructuredList->setInitializedFieldInUnion(*Field); |
| break; |
| } |
| } |
| return; |
| } |
| |
| bool InitializedSomething = false; |
| |
| // If we have any base classes, they are initialized prior to the fields. |
| for (auto &Base : Bases) { |
| Expr *Init = Index < IList->getNumInits() ? IList->getInit(Index) : nullptr; |
| SourceLocation InitLoc = Init ? Init->getLocStart() : IList->getLocEnd(); |
| |
| // Designated inits always initialize fields, so if we see one, all |
| // remaining base classes have no explicit initializer. |
| if (Init && isa<DesignatedInitExpr>(Init)) |
| Init = nullptr; |
| |
| InitializedEntity BaseEntity = InitializedEntity::InitializeBase( |
| SemaRef.Context, &Base, false, &Entity); |
| if (Init) { |
| CheckSubElementType(BaseEntity, IList, Base.getType(), Index, |
| StructuredList, StructuredIndex); |
| InitializedSomething = true; |
| } else if (VerifyOnly) { |
| CheckEmptyInitializable(BaseEntity, InitLoc); |
| } |
| } |
| |
| // If structDecl is a forward declaration, this loop won't do |
| // anything except look at designated initializers; That's okay, |
| // because an error should get printed out elsewhere. It might be |
| // worthwhile to skip over the rest of the initializer, though. |
| RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); |
| RecordDecl::field_iterator FieldEnd = RD->field_end(); |
| bool CheckForMissingFields = |
| !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); |
| |
| while (Index < IList->getNumInits()) { |
| Expr *Init = IList->getInit(Index); |
| |
| if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) { |
| // If we're not the subobject that matches up with the '{' for |
| // the designator, we shouldn't be handling the |
| // designator. Return immediately. |
| if (!SubobjectIsDesignatorContext) |
| return; |
| |
| // Handle this designated initializer. Field will be updated to |
| // the next field that we'll be initializing. |
| if (CheckDesignatedInitializer(Entity, IList, DIE, 0, |
| DeclType, &Field, nullptr, Index, |
| StructuredList, StructuredIndex, |
| true, TopLevelObject)) |
| hadError = true; |
| |
| InitializedSomething = true; |
| |
| // Disable check for missing fields when designators are used. |
| // This matches gcc behaviour. |
| CheckForMissingFields = false; |
| continue; |
| } |
| |
| if (Field == FieldEnd) { |
| // We've run out of fields. We're done. |
| break; |
| } |
| |
| // We've already initialized a member of a union. We're done. |
| if (InitializedSomething && DeclType->isUnionType()) |
| break; |
| |
| // If we've hit the flexible array member at the end, we're done. |
| if (Field->getType()->isIncompleteArrayType()) |
| break; |
| |
| if (Field->isUnnamedBitfield()) { |
| // Don't initialize unnamed bitfields, e.g. "int : 20;" |
| ++Field; |
| continue; |
| } |
| |
| // Make sure we can use this declaration. |
| bool InvalidUse; |
| if (VerifyOnly) |
| InvalidUse = !SemaRef.CanUseDecl(*Field, TreatUnavailableAsInvalid); |
| else |
| InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, |
| IList->getInit(Index)->getLocStart()); |
| if (InvalidUse) { |
| ++Index; |
| ++Field; |
| hadError = true; |
| continue; |
| } |
| |
| InitializedEntity MemberEntity = |
| InitializedEntity::InitializeMember(*Field, &Entity); |
| CheckSubElementType(MemberEntity, IList, Field->getType(), Index, |
| StructuredList, StructuredIndex); |
| InitializedSomething = true; |
| |
| if (DeclType->isUnionType() && !VerifyOnly) { |
| // Initialize the first field within the union. |
| StructuredList->setInitializedFieldInUnion(*Field); |
| } |
| |
| ++Field; |
| } |
| |
| // Emit warnings for missing struct field initializers. |
| if (!VerifyOnly && InitializedSomething && CheckForMissingFields && |
| Field != FieldEnd && !Field->getType()->isIncompleteArrayType() && |
| !DeclType->isUnionType()) { |
| // It is possible we have one or more unnamed bitfields remaining. |
| // Find first (if any) named field and emit warning. |
| for (RecordDecl::field_iterator it = Field, end = RD->field_end(); |
| it != end; ++it) { |
| if (!it->isUnnamedBitfield() && !it->hasInClassInitializer()) { |
| SemaRef.Diag(IList->getSourceRange().getEnd(), |
| diag::warn_missing_field_initializers) << *it; |
| break; |
| } |
| } |
| } |
| |
| // Check that any remaining fields can be value-initialized. |
| if (VerifyOnly && Field != FieldEnd && !DeclType->isUnionType() && |
| !Field->getType()->isIncompleteArrayType()) { |
| // FIXME: Should check for holes left by designated initializers too. |
| for (; Field != FieldEnd && !hadError; ++Field) { |
| if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer()) |
| CheckEmptyInitializable( |
| InitializedEntity::InitializeMember(*Field, &Entity), |
| IList->getLocEnd()); |
| } |
| } |
| |
| if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() || |
| Index >= IList->getNumInits()) |
| return; |
| |
| if (CheckFlexibleArrayInit(Entity, IList->getInit(Index), *Field, |
| TopLevelObject)) { |
| hadError = true; |
| ++Index; |
| return; |
| } |
| |
| InitializedEntity MemberEntity = |
| InitializedEntity::InitializeMember(*Field, &Entity); |
| |
| if (isa<InitListExpr>(IList->getInit(Index))) |
| CheckSubElementType(MemberEntity, IList, Field->getType(), Index, |
| StructuredList, StructuredIndex); |
| else |
| CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index, |
| StructuredList, 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. |
| /// |
| static void ExpandAnonymousFieldDesignator(Sema &SemaRef, |
| DesignatedInitExpr *DIE, |
| unsigned DesigIdx, |
| IndirectFieldDecl *IndirectField) { |
| typedef DesignatedInitExpr::Designator Designator; |
| |
| // Build the replacement designators. |
| SmallVector<Designator, 4> Replacements; |
| for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(), |
| PE = IndirectField->chain_end(); PI != PE; ++PI) { |
| if (PI + 1 == PE) |
| Replacements.push_back(Designator((IdentifierInfo *)nullptr, |
| DIE->getDesignator(DesigIdx)->getDotLoc(), |
| DIE->getDesignator(DesigIdx)->getFieldLoc())); |
| else |
| Replacements.push_back(Designator((IdentifierInfo *)nullptr, |
| SourceLocation(), SourceLocation())); |
| assert(isa<FieldDecl>(*PI)); |
| Replacements.back().setField(cast<FieldDecl>(*PI)); |
| } |
| |
| // 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(SemaRef.Context, DesigIdx, &Replacements[0], |
| &Replacements[0] + Replacements.size()); |
| } |
| |
| static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef, |
| DesignatedInitExpr *DIE) { |
| unsigned NumIndexExprs = DIE->getNumSubExprs() - 1; |
| SmallVector<Expr*, 4> IndexExprs(NumIndexExprs); |
| for (unsigned I = 0; I < NumIndexExprs; ++I) |
| IndexExprs[I] = DIE->getSubExpr(I + 1); |
| return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators(), |
| IndexExprs, |
| DIE->getEqualOrColonLoc(), |
| DIE->usesGNUSyntax(), DIE->getInit()); |
| } |
| |
| namespace { |
| |
| // Callback to only accept typo corrections that are for field members of |
| // the given struct or union. |
| class FieldInitializerValidatorCCC : public CorrectionCandidateCallback { |
| public: |
| explicit FieldInitializerValidatorCCC(RecordDecl *RD) |
| : Record(RD) {} |
| |
| bool ValidateCandidate(const TypoCorrection &candidate) override { |
| FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>(); |
| return FD && FD->getDeclContext()->getRedeclContext()->Equals(Record); |
| } |
| |
| private: |
| RecordDecl *Record; |
| }; |
| |
| } // end anonymous namespace |
| |
| /// @brief Check the well-formedness of a C99 designated initializer. |
| /// |
| /// Determines whether the designated initializer @p DIE, which |
| /// resides at the given @p Index within the initializer list @p |
| /// IList, is well-formed for a current object of type @p DeclType |
| /// (C99 6.7.8). The actual subobject that this designator refers to |
| /// within the current subobject is returned in either |
| /// @p NextField or @p NextElementIndex (whichever is appropriate). |
| /// |
| /// @param IList The initializer list in which this designated |
| /// initializer occurs. |
| /// |
| /// @param DIE The designated initializer expression. |
| /// |
| /// @param DesigIdx The index of the current designator. |
| /// |
| /// @param CurrentObjectType The type of the "current object" (C99 6.7.8p17), |
| /// into which the designation in @p DIE should refer. |
| /// |
| /// @param NextField If non-NULL and the first designator in @p DIE is |
| /// a field, this will be set to the field declaration corresponding |
| /// to the field named by the designator. |
| /// |
| /// @param NextElementIndex If non-NULL and the first designator in @p |
| /// DIE is an array designator or GNU array-range designator, this |
| /// will be set to the last index initialized by this designator. |
| /// |
| /// @param Index Index into @p IList where the designated initializer |
| /// @p DIE occurs. |
| /// |
| /// @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(const InitializedEntity &Entity, |
| InitListExpr *IList, |
| DesignatedInitExpr *DIE, |
| unsigned DesigIdx, |
| QualType &CurrentObjectType, |
| RecordDecl::field_iterator *NextField, |
| llvm::APSInt *NextElementIndex, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex, |
| bool FinishSubobjectInit, |
| bool TopLevelObject) { |
| if (DesigIdx == DIE->size()) { |
| // Check the actual initialization for the designated object type. |
| bool prevHadError = hadError; |
| |
| // Temporarily remove the designator expression from the |
| // initializer list that the child calls see, so that we don't try |
| // to re-process the designator. |
| unsigned OldIndex = Index; |
| IList->setInit(OldIndex, DIE->getInit()); |
| |
| CheckSubElementType(Entity, IList, CurrentObjectType, Index, |
| StructuredList, StructuredIndex); |
| |
| // Restore the designated initializer expression in the syntactic |
| // form of the initializer list. |
| if (IList->getInit(OldIndex) != DIE->getInit()) |
| DIE->setInit(IList->getInit(OldIndex)); |
| IList->setInit(OldIndex, DIE); |
| |
| return hadError && !prevHadError; |
| } |
| |
| DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx); |
| bool IsFirstDesignator = (DesigIdx == 0); |
| if (!VerifyOnly) { |
| assert((IsFirstDesignator || StructuredList) && |
| "Need a non-designated initializer list to start from"); |
| |
| // Determine the structural initializer list that corresponds to the |
| // current subobject. |
| if (IsFirstDesignator) |
| StructuredList = SyntacticToSemantic.lookup(IList); |
| else { |
| Expr *ExistingInit = StructuredIndex < StructuredList->getNumInits() ? |
| StructuredList->getInit(StructuredIndex) : nullptr; |
| if (!ExistingInit && StructuredList->hasArrayFiller()) |
| ExistingInit = StructuredList->getArrayFiller(); |
| |
| if (!ExistingInit) |
| StructuredList = |
| getStructuredSubobjectInit(IList, Index, CurrentObjectType, |
| StructuredList, StructuredIndex, |
| SourceRange(D->getLocStart(), |
| DIE->getLocEnd())); |
| else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit)) |
| StructuredList = Result; |
| else { |
| if (DesignatedInitUpdateExpr *E = |
| dyn_cast<DesignatedInitUpdateExpr>(ExistingInit)) |
| StructuredList = E->getUpdater(); |
| else { |
| DesignatedInitUpdateExpr *DIUE = |
| new (SemaRef.Context) DesignatedInitUpdateExpr(SemaRef.Context, |
| D->getLocStart(), ExistingInit, |
| DIE->getLocEnd()); |
| StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE); |
| StructuredList = DIUE->getUpdater(); |
| } |
| |
| // We need to check on source range validity because the previous |
| // initializer does not have to be an explicit initializer. e.g., |
| // |
| // struct P { int a, b; }; |
| // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 }; |
| // |
| // There is an overwrite taking place because the first braced initializer |
| // list "{ .a = 2 }" already provides value for .p.b (which is zero). |
| if (ExistingInit->getSourceRange().isValid()) { |
| // 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(D->getLocStart(), |
| diag::warn_subobject_initializer_overrides) |
| << SourceRange(D->getLocStart(), DIE->getLocEnd()); |
| |
| SemaRef.Diag(ExistingInit->getLocStart(), |
| diag::note_previous_initializer) |
| << /*FIXME:has side effects=*/0 |
| << ExistingInit->getSourceRange(); |
| } |
| } |
| } |
| assert(StructuredList && "Expected a structured initializer list"); |
| } |
| |
| if (D->isFieldDesignator()) { |
| // C99 6.7.8p7: |
| // |
| // If a designator has the form |
| // |
| // . identifier |
| // |
| // then the current object (defined below) shall have |
| // structure or union type and the identifier shall be the |
| // name of a member of that type. |
| const RecordType *RT = CurrentObjectType->getAs<RecordType>(); |
| if (!RT) { |
| SourceLocation Loc = D->getDotLoc(); |
| if (Loc.isInvalid()) |
| Loc = D->getFieldLoc(); |
| if (!VerifyOnly) |
| SemaRef.Diag(Loc, diag::err_field_designator_non_aggr) |
| << SemaRef.getLangOpts().CPlusPlus << CurrentObjectType; |
| ++Index; |
| return true; |
| } |
| |
| FieldDecl *KnownField = D->getField(); |
| if (!KnownField) { |
| IdentifierInfo *FieldName = D->getFieldName(); |
| DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); |
| for (NamedDecl *ND : Lookup) { |
| if (auto *FD = dyn_cast<FieldDecl>(ND)) { |
| KnownField = FD; |
| break; |
| } |
| if (auto *IFD = dyn_cast<IndirectFieldDecl>(ND)) { |
| // In verify mode, don't modify the original. |
| if (VerifyOnly) |
| DIE = CloneDesignatedInitExpr(SemaRef, DIE); |
| ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IFD); |
| D = DIE->getDesignator(DesigIdx); |
| KnownField = cast<FieldDecl>(*IFD->chain_begin()); |
| break; |
| } |
| } |
| if (!KnownField) { |
| if (VerifyOnly) { |
| ++Index; |
| return true; // No typo correction when just trying this out. |
| } |
| |
| // Name lookup found something, but it wasn't a field. |
| if (!Lookup.empty()) { |
| SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) |
| << FieldName; |
| SemaRef.Diag(Lookup.front()->getLocation(), |
| diag::note_field_designator_found); |
| ++Index; |
| return true; |
| } |
| |
| // Name lookup didn't find anything. |
| // Determine whether this was a typo for another field name. |
| if (TypoCorrection Corrected = SemaRef.CorrectTypo( |
| DeclarationNameInfo(FieldName, D->getFieldLoc()), |
| Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, |
| llvm::make_unique<FieldInitializerValidatorCCC>(RT->getDecl()), |
| Sema::CTK_ErrorRecovery, RT->getDecl())) { |
| SemaRef.diagnoseTypo( |
| Corrected, |
| SemaRef.PDiag(diag::err_field_designator_unknown_suggest) |
| << FieldName << CurrentObjectType); |
| KnownField = Corrected.getCorrectionDeclAs<FieldDecl>(); |
| hadError = true; |
| } else { |
| // Typo correction didn't find anything. |
| SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) |
| << FieldName << CurrentObjectType; |
| ++Index; |
| return true; |
| } |
| } |
| } |
| |
| unsigned FieldIndex = 0; |
| |
| if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl())) |
| FieldIndex = CXXRD->getNumBases(); |
| |
| for (auto *FI : RT->getDecl()->fields()) { |
| if (FI->isUnnamedBitfield()) |
| continue; |
| if (declaresSameEntity(KnownField, FI)) { |
| KnownField = FI; |
| break; |
| } |
| ++FieldIndex; |
| } |
| |
| RecordDecl::field_iterator Field = |
| RecordDecl::field_iterator(DeclContext::decl_iterator(KnownField)); |
| |
| // All of the fields of a union are located at the same place in |
| // the initializer list. |
| if (RT->getDecl()->isUnion()) { |
| FieldIndex = 0; |
| if (!VerifyOnly) { |
| FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion(); |
| if (CurrentField && !declaresSameEntity(CurrentField, *Field)) { |
| assert(StructuredList->getNumInits() == 1 |
| && "A union should never have more than one initializer!"); |
| |
| Expr *ExistingInit = StructuredList->getInit(0); |
| if (ExistingInit) { |
| // We're about to throw away an initializer, emit warning. |
| SemaRef.Diag(D->getFieldLoc(), |
| diag::warn_initializer_overrides) |
| << D->getSourceRange(); |
| SemaRef.Diag(ExistingInit->getLocStart(), |
| diag::note_previous_initializer) |
| << /*FIXME:has side effects=*/0 |
| << ExistingInit->getSourceRange(); |
| } |
| |
| // remove existing initializer |
| StructuredList->resizeInits(SemaRef.Context, 0); |
| StructuredList->setInitializedFieldInUnion(nullptr); |
| } |
| |
| StructuredList->setInitializedFieldInUnion(*Field); |
| } |
| } |
| |
| // Make sure we can use this declaration. |
| bool InvalidUse; |
| if (VerifyOnly) |
| InvalidUse = !SemaRef.CanUseDecl(*Field, TreatUnavailableAsInvalid); |
| else |
| InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc()); |
| if (InvalidUse) { |
| ++Index; |
| return true; |
| } |
| |
| if (!VerifyOnly) { |
| // Update the designator with the field declaration. |
| 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); |
| } |
| |
| // This designator names a flexible array member. |
| if (Field->getType()->isIncompleteArrayType()) { |
| bool Invalid = false; |
| if ((DesigIdx + 1) != DIE->size()) { |
| // We can't designate an object within the flexible array |
| // member (because GCC doesn't allow it). |
| if (!VerifyOnly) { |
| DesignatedInitExpr::Designator *NextD |
| = DIE->getDesignator(DesigIdx + 1); |
| SemaRef.Diag(NextD->getLocStart(), |
| diag::err_designator_into_flexible_array_member) |
| << SourceRange(NextD->getLocStart(), |
| DIE->getLocEnd()); |
| SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) |
| << *Field; |
| } |
| Invalid = true; |
| } |
| |
| if (!hadError && !isa<InitListExpr>(DIE->getInit()) && |
| !isa<StringLiteral>(DIE->getInit())) { |
| // The initializer is not an initializer list. |
| if (!VerifyOnly) { |
| SemaRef.Diag(DIE->getInit()->getLocStart(), |
| diag::err_flexible_array_init_needs_braces) |
| << DIE->getInit()->getSourceRange(); |
| SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) |
| << *Field; |
| } |
| Invalid = true; |
| } |
| |
| // Check GNU flexible array initializer. |
| if (!Invalid && CheckFlexibleArrayInit(Entity, DIE->getInit(), *Field, |
| TopLevelObject)) |
| Invalid = true; |
| |
| if (Invalid) { |
| ++Index; |
| return true; |
| } |
| |
| // Initialize the array. |
| bool prevHadError = hadError; |
| unsigned newStructuredIndex = FieldIndex; |
| unsigned OldIndex = Index; |
| IList->setInit(Index, DIE->getInit()); |
| |
| InitializedEntity MemberEntity = |
| InitializedEntity::InitializeMember(*Field, &Entity); |
| CheckSubElementType(MemberEntity, IList, Field->getType(), Index, |
| StructuredList, newStructuredIndex); |
| |
| IList->setInit(OldIndex, DIE); |
| if (hadError && !prevHadError) { |
| ++Field; |
| ++FieldIndex; |
| if (NextField) |
| *NextField = Field; |
| StructuredIndex = FieldIndex; |
| return true; |
| } |
| } else { |
| // Recurse to check later designated subobjects. |
| QualType FieldType = Field->getType(); |
| unsigned newStructuredIndex = FieldIndex; |
| |
| InitializedEntity MemberEntity = |
| InitializedEntity::InitializeMember(*Field, &Entity); |
| if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1, |
| FieldType, nullptr, nullptr, Index, |
| StructuredList, newStructuredIndex, |
| FinishSubobjectInit, false)) |
| return true; |
| } |
| |
| // Find the position of the next field to be initialized in this |
| // subobject. |
| ++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; |
| } |
| |
| 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; |
| |
| auto NoBases = |
| CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(), |
| CXXRecordDecl::base_class_iterator()); |
| CheckStructUnionTypes(Entity, IList, CurrentObjectType, NoBases, Field, |
| false, Index, StructuredList, FieldIndex); |
| return hadError && !prevHadError; |
| } |
| |
| // C99 6.7.8p6: |
| // |
| // If a designator has the form |
| // |
| // [ constant-expression ] |
| // |
| // then the current object (defined below) shall have array |
| // type and the expression shall be an integer constant |
| // expression. If the array is of unknown size, any |
| // nonnegative value is valid. |
| // |
| // Additionally, cope with the GNU extension that permits |
| // designators of the form |
| // |
| // [ constant-expression ... constant-expression ] |
| const ArrayType *AT = SemaRef.Context.getAsArrayType(CurrentObjectType); |
| if (!AT) { |
| if (!VerifyOnly) |
| SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array) |
| << CurrentObjectType; |
| ++Index; |
| return true; |
| } |
| |
| Expr *IndexExpr = nullptr; |
| llvm::APSInt DesignatedStartIndex, DesignatedEndIndex; |
| if (D->isArrayDesignator()) { |
| IndexExpr = DIE->getArrayIndex(*D); |
| DesignatedStartIndex = IndexExpr->EvaluateKnownConstInt(SemaRef.Context); |
| DesignatedEndIndex = DesignatedStartIndex; |
| } else { |
| assert(D->isArrayRangeDesignator() && "Need array-range designator"); |
| |
| DesignatedStartIndex = |
| DIE->getArrayRangeStart(*D)->EvaluateKnownConstInt(SemaRef.Context); |
| DesignatedEndIndex = |
| DIE->getArrayRangeEnd(*D)->EvaluateKnownConstInt(SemaRef.Context); |
| IndexExpr = DIE->getArrayRangeEnd(*D); |
| |
| // Codegen can't handle evaluating array range designators that have side |
| // effects, because we replicate the AST value for each initialized element. |
| // As such, set the sawArrayRangeDesignator() bit if we initialize multiple |
| // elements with something that has a side effect, so codegen can emit an |
| // "error unsupported" error instead of miscompiling the app. |
| if (DesignatedStartIndex.getZExtValue()!=DesignatedEndIndex.getZExtValue()&& |
| DIE->getInit()->HasSideEffects(SemaRef.Context) && !VerifyOnly) |
| FullyStructuredList->sawArrayRangeDesignator(); |
| } |
| |
| if (isa<ConstantArrayType>(AT)) { |
| llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false); |
| DesignatedStartIndex |
| = DesignatedStartIndex.extOrTrunc(MaxElements.getBitWidth()); |
| DesignatedStartIndex.setIsUnsigned(MaxElements.isUnsigned()); |
| DesignatedEndIndex |
| = DesignatedEndIndex.extOrTrunc(MaxElements.getBitWidth()); |
| DesignatedEndIndex.setIsUnsigned(MaxElements.isUnsigned()); |
| if (DesignatedEndIndex >= MaxElements) { |
| if (!VerifyOnly) |
| SemaRef.Diag(IndexExpr->getLocStart(), |
| diag::err_array_designator_too_large) |
| << DesignatedEndIndex.toString(10) << MaxElements.toString(10) |
| << IndexExpr->getSourceRange(); |
| ++Index; |
| return true; |
| } |
| } else { |
| unsigned DesignatedIndexBitWidth = |
| ConstantArrayType::getMaxSizeBits(SemaRef.Context); |
| DesignatedStartIndex = |
| DesignatedStartIndex.extOrTrunc(DesignatedIndexBitWidth); |
| DesignatedEndIndex = |
| DesignatedEndIndex.extOrTrunc(DesignatedIndexBitWidth); |
| DesignatedStartIndex.setIsUnsigned(true); |
| DesignatedEndIndex.setIsUnsigned(true); |
| } |
| |
| if (!VerifyOnly && StructuredList->isStringLiteralInit()) { |
| // We're modifying a string literal init; we have to decompose the string |
| // so we can modify the individual characters. |
| ASTContext &Context = SemaRef.Context; |
| Expr *SubExpr = StructuredList->getInit(0)->IgnoreParens(); |
| |
| // Compute the character type |
| QualType CharTy = AT->getElementType(); |
| |
| // Compute the type of the integer literals. |
| QualType PromotedCharTy = CharTy; |
| if (CharTy->isPromotableIntegerType()) |
| PromotedCharTy = Context.getPromotedIntegerType(CharTy); |
| unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy); |
| |
| if (StringLiteral *SL = dyn_cast<StringLiteral>(SubExpr)) { |
| // Get the length of the string. |
| uint64_t StrLen = SL->getLength(); |
| if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen)) |
| StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue(); |
| StructuredList->resizeInits(Context, StrLen); |
| |
| // Build a literal for each character in the string, and put them into |
| // the init list. |
| for (unsigned i = 0, e = StrLen; i != e; ++i) { |
| llvm::APInt CodeUnit(PromotedCharTyWidth, SL->getCodeUnit(i)); |
| Expr *Init = new (Context) IntegerLiteral( |
| Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc()); |
| if (CharTy != PromotedCharTy) |
| Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast, |
| Init, nullptr, VK_RValue); |
| StructuredList->updateInit(Context, i, Init); |
| } |
| } else { |
| ObjCEncodeExpr *E = cast<ObjCEncodeExpr>(SubExpr); |
| std::string Str; |
| Context.getObjCEncodingForType(E->getEncodedType(), Str); |
| |
| // Get the length of the string. |
| uint64_t StrLen = Str.size(); |
| if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen)) |
| StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue(); |
| StructuredList->resizeInits(Context, StrLen); |
| |
| // Build a literal for each character in the string, and put them into |
| // the init list. |
| for (unsigned i = 0, e = StrLen; i != e; ++i) { |
| llvm::APInt CodeUnit(PromotedCharTyWidth, Str[i]); |
| Expr *Init = new (Context) IntegerLiteral( |
| Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc()); |
| if (CharTy != PromotedCharTy) |
| Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast, |
| Init, nullptr, VK_RValue); |
| StructuredList->updateInit(Context, i, Init); |
| } |
| } |
| } |
| |
| // Make sure that our non-designated initializer list has space |
| // for a subobject corresponding to this array element. |
| if (!VerifyOnly && |
| DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits()) |
| StructuredList->resizeInits(SemaRef.Context, |
| DesignatedEndIndex.getZExtValue() + 1); |
| |
| // Repeatedly perform subobject initializations in the range |
| // [DesignatedStartIndex, DesignatedEndIndex]. |
| |
| // Move to the next designator |
| unsigned ElementIndex = DesignatedStartIndex.getZExtValue(); |
| unsigned OldIndex = Index; |
| |
| InitializedEntity ElementEntity = |
| InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); |
| |
| while (DesignatedStartIndex <= DesignatedEndIndex) { |
| // Recurse to check later designated subobjects. |
| QualType ElementType = AT->getElementType(); |
| Index = OldIndex; |
| |
| ElementEntity.setElementIndex(ElementIndex); |
| if (CheckDesignatedInitializer( |
| ElementEntity, IList, DIE, DesigIdx + 1, ElementType, nullptr, |
| nullptr, Index, StructuredList, ElementIndex, |
| FinishSubobjectInit && (DesignatedStartIndex == DesignatedEndIndex), |
| false)) |
| return true; |
| |
| // Move to the next index in the array that we'll be initializing. |
| ++DesignatedStartIndex; |
| ElementIndex = DesignatedStartIndex.getZExtValue(); |
| } |
| |
| // If this the first designator, our caller will continue checking |
| // the rest of this array subobject. |
| if (IsFirstDesignator) { |
| if (NextElementIndex) |
| *NextElementIndex = DesignatedStartIndex; |
| StructuredIndex = ElementIndex; |
| return false; |
| } |
| |
| if (!FinishSubobjectInit) |
| return false; |
| |
| // Check the remaining elements within this array subobject. |
| bool prevHadError = hadError; |
| CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex, |
| /*SubobjectIsDesignatorContext=*/false, 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, |
| bool IsFullyOverwritten) { |
| if (VerifyOnly) |
| return nullptr; // No structured list in verification-only mode. |
| Expr *ExistingInit = nullptr; |
| if (!StructuredList) |
| ExistingInit = SyntacticToSemantic.lookup(IList); |
| else if (StructuredIndex < StructuredList->getNumInits()) |
| ExistingInit = StructuredList->getInit(StructuredIndex); |
| |
| if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit)) |
| // There might have already been initializers for subobjects of the current |
| // object, but a subsequent initializer list will overwrite the entirety |
| // of the current object. (See DR 253 and C99 6.7.8p21). e.g., |
| // |
| // struct P { char x[6]; }; |
| // struct P l = { .x[2] = 'x', .x = { [0] = 'f' } }; |
| // |
| // The first designated initializer is ignored, and l.x is just "f". |
| if (!IsFullyOverwritten) |
| 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->getLocStart(), |
| diag::note_previous_initializer) |
| << /*FIXME:has side effects=*/0 |
| << ExistingInit->getSourceRange(); |
| } |
| |
| InitListExpr *Result |
| = new (SemaRef.Context) InitListExpr(SemaRef.Context, |
| InitRange.getBegin(), None, |
| InitRange.getEnd()); |
| |
| QualType ResultType = CurrentObjectType; |
| if (!ResultType->isArrayType()) |
| ResultType = ResultType.getNonLValueExprType(SemaRef.Context); |
| Result->setType(ResultType); |
| |
| // Pre-allocate storage for the structured initializer list. |
| unsigned NumElements = 0; |
| unsigned NumInits = 0; |
| bool GotNumInits = false; |
| |