| //===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // 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/ExprOpenMP.h" |
| #include "clang/AST/TypeLoc.h" |
| #include "clang/Basic/CharInfo.h" |
| #include "clang/Basic/SourceManager.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/PointerIntPair.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| using namespace clang; |
| |
| //===----------------------------------------------------------------------===// |
| // Sema Initialization Checking |
| //===----------------------------------------------------------------------===// |
| |
| /// 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_UTF8StringIntoPlainChar, |
| SIF_PlainStringIntoUTF8Char, |
| SIF_Other |
| }; |
| |
| /// 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::UTF8: |
| // char8_t array can be initialized with a UTF-8 string. |
| if (ElemTy->isChar8Type()) |
| return SIF_None; |
| LLVM_FALLTHROUGH; |
| case StringLiteral::Ascii: |
| // char array can be initialized with a narrow string. |
| // Only allow char x[] = "foo"; not char x[] = L"foo"; |
| if (ElemTy->isCharType()) |
| return (SL->getKind() == StringLiteral::UTF8 && |
| Context.getLangOpts().Char8) |
| ? SIF_UTF8StringIntoPlainChar |
| : SIF_None; |
| if (ElemTy->isChar8Type()) |
| return SIF_PlainStringIntoUTF8Char; |
| 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() || ElemTy->isChar8Type()) |
| 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() || ElemTy->isChar8Type()) |
| 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() || ElemTy->isChar8Type()) |
| 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); |
| } |
| |
| bool Sema::IsStringInit(Expr *Init, const ArrayType *AT) { |
| return ::IsStringInit(Init, AT, Context) == SIF_None; |
| } |
| |
| /// 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); |
| E->setValueKind(VK_PRValue); |
| 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)) { |
| assert(UO->getOpcode() == UO_Extension); |
| E = UO->getSubExpr(); |
| } else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) { |
| E = GSE->getResultExpr(); |
| } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) { |
| E = CE->getChosenSubExpr(); |
| } else { |
| llvm_unreachable("unexpected expr in string literal init"); |
| } |
| } |
| } |
| |
| /// Fix a compound literal initializing an array so it's correctly marked |
| /// as an rvalue. |
| static void updateGNUCompoundLiteralRValue(Expr *E) { |
| while (true) { |
| E->setValueKind(VK_PRValue); |
| if (isa<CompoundLiteralExpr>(E)) { |
| break; |
| } else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { |
| E = PE->getSubExpr(); |
| } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { |
| assert(UO->getOpcode() == UO_Extension); |
| E = UO->getSubExpr(); |
| } else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) { |
| E = GSE->getResultExpr(); |
| } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) { |
| E = CE->getChosenSubExpr(); |
| } else { |
| llvm_unreachable("unexpected expr in array compound 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, nullptr, |
| 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->getBeginLoc(), |
| 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->getBeginLoc(), |
| 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 { |
| |
| /// 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. |
| /// |
| /// If an initializer list contains any designators, we build a placeholder |
| /// structured list even in 'verify only' mode, so that we can track which |
| /// elements need 'empty' initializtion. |
| class InitListChecker { |
| Sema &SemaRef; |
| bool hadError = false; |
| bool VerifyOnly; // No diagnostics. |
| bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode. |
| bool InOverloadResolution; |
| InitListExpr *FullyStructuredList = nullptr; |
| NoInitExpr *DummyExpr = nullptr; |
| |
| NoInitExpr *getDummyInit() { |
| if (!DummyExpr) |
| DummyExpr = new (SemaRef.Context) NoInitExpr(SemaRef.Context.VoidTy); |
| return DummyExpr; |
| } |
| |
| 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, |
| bool DirectlyDesignated = false); |
| 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); |
| InitListExpr *createInitListExpr(QualType CurrentObjectType, |
| SourceRange InitRange, |
| unsigned ExpectedNumInits); |
| int numArrayElements(QualType DeclType); |
| int numStructUnionElements(QualType DeclType); |
| |
| ExprResult PerformEmptyInit(SourceLocation Loc, |
| const InitializedEntity &Entity); |
| |
| /// Diagnose that OldInit (or part thereof) has been overridden by NewInit. |
| void diagnoseInitOverride(Expr *OldInit, SourceRange NewInitRange, |
| bool FullyOverwritten = true) { |
| // Overriding an initializer via a designator is valid with C99 designated |
| // initializers, but ill-formed with C++20 designated initializers. |
| unsigned DiagID = SemaRef.getLangOpts().CPlusPlus |
| ? diag::ext_initializer_overrides |
| : diag::warn_initializer_overrides; |
| |
| if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) { |
| // In overload resolution, we have to strictly enforce the rules, and so |
| // don't allow any overriding of prior initializers. This matters for a |
| // case such as: |
| // |
| // union U { int a, b; }; |
| // struct S { int a, b; }; |
| // void f(U), f(S); |
| // |
| // Here, f({.a = 1, .b = 2}) is required to call the struct overload. For |
| // consistency, we disallow all overriding of prior initializers in |
| // overload resolution, not only overriding of union members. |
| hadError = true; |
| } else if (OldInit->getType().isDestructedType() && !FullyOverwritten) { |
| // If we'll be keeping around the old initializer but overwriting part of |
| // the object it initialized, and that object is not trivially |
| // destructible, this can leak. Don't allow that, not even as an |
| // extension. |
| // |
| // FIXME: It might be reasonable to allow this in cases where the part of |
| // the initializer that we're overriding has trivial destruction. |
| DiagID = diag::err_initializer_overrides_destructed; |
| } else if (!OldInit->getSourceRange().isValid()) { |
| // 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). |
| // |
| // Such overwrites are harmless, so we don't diagnose them. (Note that in |
| // C++, this cannot be reached unless we've already seen and diagnosed a |
| // different conformance issue, such as a mixture of designated and |
| // non-designated initializers or a multi-level designator.) |
| return; |
| } |
| |
| if (!VerifyOnly) { |
| SemaRef.Diag(NewInitRange.getBegin(), DiagID) |
| << NewInitRange << FullyOverwritten << OldInit->getType(); |
| SemaRef.Diag(OldInit->getBeginLoc(), diag::note_previous_initializer) |
| << (OldInit->HasSideEffects(SemaRef.Context) && FullyOverwritten) |
| << OldInit->getSourceRange(); |
| } |
| } |
| |
| // 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 InOverloadResolution = false); |
| bool HadError() { return hadError; } |
| |
| // Retrieves the fully-structured initializer list used for |
| // semantic analysis and code generation. |
| InitListExpr *getFullyStructuredList() const { return FullyStructuredList; } |
| }; |
| |
| } // end anonymous namespace |
| |
| ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, |
| const InitializedEntity &Entity) { |
| 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(); |
| } |
| } |
| hadError = true; |
| return ExprError(); |
| } |
| |
| return VerifyOnly ? ExprResult() |
| : InitSeq.Perform(SemaRef, Entity, Kind, SubInit); |
| } |
| |
| void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity, |
| SourceLocation Loc) { |
| // If we're building a fully-structured list, we'll check this at the end |
| // once we know which elements are actually initialized. Otherwise, we know |
| // that there are no designators so we can just check now. |
| if (FullyStructuredList) |
| return; |
| PerformEmptyInit(Loc, Entity); |
| } |
| |
| void InitListChecker::FillInEmptyInitForBase( |
| unsigned Init, const CXXBaseSpecifier &Base, |
| const InitializedEntity &ParentEntity, InitListExpr *ILE, |
| bool &RequiresSecondPass, bool FillWithNoInit) { |
| InitializedEntity BaseEntity = InitializedEntity::InitializeBase( |
| SemaRef.Context, &Base, false, &ParentEntity); |
| |
| if (Init >= ILE->getNumInits() || !ILE->getInit(Init)) { |
| ExprResult BaseInit = FillWithNoInit |
| ? new (SemaRef.Context) NoInitExpr(Base.getType()) |
| : PerformEmptyInit(ILE->getEndLoc(), BaseEntity); |
| if (BaseInit.isInvalid()) { |
| hadError = true; |
| return; |
| } |
| |
| if (!VerifyOnly) { |
| assert(Init < ILE->getNumInits() && "should have been expanded"); |
| 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->getEndLoc(); |
| unsigned NumInits = ILE->getNumInits(); |
| InitializedEntity MemberEntity |
| = InitializedEntity::InitializeMember(Field, &ParentEntity); |
| |
| if (Init >= NumInits || !ILE->getInit(Init)) { |
| if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) |
| if (!RType->getDecl()->isUnion()) |
| assert((Init < NumInits || VerifyOnly) && |
| "This ILE should have been expanded"); |
| |
| if (FillWithNoInit) { |
| assert(!VerifyOnly && "should not fill with no-init in verify-only mode"); |
| 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()) { |
| if (VerifyOnly) |
| return; |
| |
| ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field); |
| if (DIE.isInvalid()) { |
| hadError = true; |
| return; |
| } |
| SemaRef.checkInitializerLifetime(MemberEntity, DIE.get()); |
| if (Init < NumInits) |
| ILE->setInit(Init, DIE.get()); |
| else { |
| ILE->updateInit(SemaRef.Context, Init, DIE.get()); |
| RequiresSecondPass = true; |
| } |
| return; |
| } |
| |
| if (Field->getType()->isReferenceType()) { |
| if (!VerifyOnly) { |
| // 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(Loc, MemberEntity); |
| if (MemberInit.isInvalid()) { |
| hadError = true; |
| return; |
| } |
| |
| if (hadError || VerifyOnly) { |
| // 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"); |
| |
| // We don't need to do any checks when just filling NoInitExprs; that can't |
| // fail. |
| if (FillWithNoInit && VerifyOnly) |
| return; |
| |
| // 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 (!VerifyOnly && 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(); |
| |
| bool SkipEmptyInitChecks = false; |
| for (unsigned Init = 0; Init != NumElements; ++Init) { |
| if (hadError) |
| return; |
| |
| if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement || |
| ElementEntity.getKind() == InitializedEntity::EK_VectorElement) |
| ElementEntity.setElementIndex(Init); |
| |
| if (Init >= NumInits && (ILE->hasArrayFiller() || SkipEmptyInitChecks)) |
| return; |
| |
| Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr); |
| if (!InitExpr && Init < NumInits && ILE->hasArrayFiller()) |
| ILE->setInit(Init, ILE->getArrayFiller()); |
| else if (!InitExpr && !ILE->hasArrayFiller()) { |
| // In VerifyOnly mode, there's no point performing empty initialization |
| // more than once. |
| if (SkipEmptyInitChecks) |
| continue; |
| |
| Expr *Filler = nullptr; |
| |
| if (FillWithNoInit) |
| Filler = new (SemaRef.Context) NoInitExpr(ElementType); |
| else { |
| ExprResult ElementInit = |
| PerformEmptyInit(ILE->getEndLoc(), ElementEntity); |
| if (ElementInit.isInvalid()) { |
| hadError = true; |
| return; |
| } |
| |
| Filler = ElementInit.getAs<Expr>(); |
| } |
| |
| if (hadError) { |
| // Do nothing |
| } else if (VerifyOnly) { |
| SkipEmptyInitChecks = true; |
| } 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); |
| } |
| } |
| } |
| |
| static bool hasAnyDesignatedInits(const InitListExpr *IL) { |
| for (const Stmt *Init : *IL) |
| if (Init && isa<DesignatedInitExpr>(Init)) |
| return true; |
| return false; |
| } |
| |
| InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, |
| InitListExpr *IL, QualType &T, bool VerifyOnly, |
| bool TreatUnavailableAsInvalid, |
| bool InOverloadResolution) |
| : SemaRef(S), VerifyOnly(VerifyOnly), |
| TreatUnavailableAsInvalid(TreatUnavailableAsInvalid), |
| InOverloadResolution(InOverloadResolution) { |
| if (!VerifyOnly || hasAnyDesignatedInits(IL)) { |
| FullyStructuredList = |
| createInitListExpr(T, IL->getSourceRange(), IL->getNumInits()); |
| |
| // FIXME: Check that IL isn't already the semantic form of some other |
| // InitListExpr. If it is, we'd create a broken AST. |
| if (!VerifyOnly) |
| FullyStructuredList->setSyntacticForm(IL); |
| } |
| |
| CheckExplicitInitList(Entity, IL, T, FullyStructuredList, |
| /*TopLevelObject=*/true); |
| |
| if (!hadError && FullyStructuredList) { |
| bool RequiresSecondPass = false; |
| FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass, |
| /*OuterILE=*/nullptr, /*OuterIndex=*/0); |
| if (RequiresSecondPass && !hadError) |
| FillInEmptyInitializations(Entity, FullyStructuredList, |
| RequiresSecondPass, nullptr, 0); |
| } |
| if (hadError && FullyStructuredList) |
| FullyStructuredList->markError(); |
| } |
| |
| 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->castAs<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. |
| |
| if (!Entity.getParent()) |
| return false; |
| |
| // Allows elide brace initialization for aggregates with empty base. |
| if (Entity.getKind() == InitializedEntity::EK_Base) { |
| auto *ParentRD = |
| Entity.getParent()->getType()->castAs<RecordType>()->getDecl(); |
| CXXRecordDecl *CXXRD = cast<CXXRecordDecl>(ParentRD); |
| return CXXRD->getNumBases() == 1 && CXXRD->field_empty(); |
| } |
| |
| // Allow brace elision if the only subobject is a field. |
| if (Entity.getKind() == InitializedEntity::EK_Member) { |
| 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(); |
| } |
| |
| return false; |
| } |
| |
| /// 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->castAs<VectorType>()->getNumElements(); |
| else |
| llvm_unreachable("CheckImplicitInitList(): Illegal type"); |
| |
| if (maxElements == 0) { |
| if (!VerifyOnly) |
| SemaRef.Diag(ParentIList->getInit(Index)->getBeginLoc(), |
| 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)->getBeginLoc(), |
| 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 (StructuredSubobjectInitList) { |
| 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 (!VerifyOnly && (T->isArrayType() || T->isRecordType()) && |
| !ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && |
| !isIdiomaticBraceElisionEntity(Entity)) { |
| SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(), |
| diag::warn_missing_braces) |
| << StructuredSubobjectInitList->getSourceRange() |
| << FixItHint::CreateInsertion( |
| StructuredSubobjectInitList->getBeginLoc(), "{") |
| << FixItHint::CreateInsertion( |
| SemaRef.getLocForEndOfToken( |
| StructuredSubobjectInitList->getEndLoc()), |
| "}"); |
| } |
| |
| // Warn if this type won't be an aggregate in future versions of C++. |
| auto *CXXRD = T->getAsCXXRecordDecl(); |
| if (!VerifyOnly && CXXRD && CXXRD->hasUserDeclaredConstructor()) { |
| SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(), |
| diag::warn_cxx20_compat_aggregate_init_with_ctors) |
| << StructuredSubobjectInitList->getSourceRange() << T; |
| } |
| } |
| } |
| |
| /// 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_TemplateParameter: |
| case InitializedEntity::EK_Result: |
| // Extra braces here are suspicious. |
| DiagID = diag::warn_braces_around_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_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: |
| case InitializedEntity::EK_StmtExprResult: |
| llvm_unreachable("unexpected braced scalar init"); |
| } |
| |
| if (DiagID) { |
| S.Diag(Braces.getBegin(), DiagID) |
| << Entity.getType()->isSizelessBuiltinType() << 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) { |
| unsigned Index = 0, StructuredIndex = 0; |
| CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, |
| Index, StructuredList, StructuredIndex, TopLevelObject); |
| if (StructuredList) { |
| QualType ExprTy = T; |
| if (!ExprTy->isArrayType()) |
| ExprTy = ExprTy.getNonLValueExprType(SemaRef.Context); |
| if (!VerifyOnly) |
| IList->setType(ExprTy); |
| StructuredList->setType(ExprTy); |
| } |
| if (hadError) |
| return; |
| |
| // Don't complain for incomplete types, since we'll get an error elsewhere. |
| if (Index < IList->getNumInits() && !T->isIncompleteType()) { |
| // We have leftover initializers |
| bool ExtraInitsIsError = SemaRef.getLangOpts().CPlusPlus || |
| (SemaRef.getLangOpts().OpenCL && T->isVectorType()); |
| hadError = ExtraInitsIsError; |
| if (VerifyOnly) { |
| return; |
| } else if (StructuredIndex == 1 && |
| IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) == |
| SIF_None) { |
| unsigned DK = |
| ExtraInitsIsError |
| ? diag::err_excess_initializers_in_char_array_initializer |
| : diag::ext_excess_initializers_in_char_array_initializer; |
| SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) |
| << IList->getInit(Index)->getSourceRange(); |
| } else if (T->isSizelessBuiltinType()) { |
| unsigned DK = ExtraInitsIsError |
| ? diag::err_excess_initializers_for_sizeless_type |
| : diag::ext_excess_initializers_for_sizeless_type; |
| SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) |
| << T << IList->getInit(Index)->getSourceRange(); |
| } else { |
| int initKind = T->isArrayType() ? 0 : |
| T->isVectorType() ? 1 : |
| T->isScalarType() ? 2 : |
| T->isUnionType() ? 3 : |
| 4; |
| |
| unsigned DK = ExtraInitsIsError ? diag::err_excess_initializers |
| : diag::ext_excess_initializers; |
| SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) |
| << initKind << IList->getInit(Index)->getSourceRange(); |
| } |
| } |
| |
| if (!VerifyOnly) { |
| if (T->isScalarType() && IList->getNumInits() == 1 && |
| !isa<InitListExpr>(IList->getInit(0))) |
| warnBracedScalarInit(SemaRef, Entity, IList->getSourceRange()); |
| |
| // Warn if this is a class type that won't be an aggregate in future |
| // versions of C++. |
| auto *CXXRD = T->getAsCXXRecordDecl(); |
| if (CXXRD && CXXRD->hasUserDeclaredConstructor()) { |
| // Don't warn if there's an equivalent default constructor that would be |
| // used instead. |
| bool HasEquivCtor = false; |
| if (IList->getNumInits() == 0) { |
| auto *CD = SemaRef.LookupDefaultConstructor(CXXRD); |
| HasEquivCtor = CD && !CD->isDeleted(); |
| } |
| |
| if (!HasEquivCtor) { |
| SemaRef.Diag(IList->getBeginLoc(), |
| diag::warn_cxx20_compat_aggregate_init_with_ctors) |
| << IList->getSourceRange() << T; |
| } |
| } |
| } |
| } |
| |
| 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->castAs<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->getBeginLoc(), 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->getBeginLoc(), diag::err_init_objc_class) << DeclType; |
| hadError = true; |
| } else if (DeclType->isOCLIntelSubgroupAVCType() || |
| DeclType->isSizelessBuiltinType()) { |
| // Checks for scalar type are sufficient for these types too. |
| CheckScalarType(Entity, IList, DeclType, Index, StructuredList, |
| StructuredIndex); |
| } else { |
| if (!VerifyOnly) |
| SemaRef.Diag(IList->getBeginLoc(), diag::err_illegal_initializer_type) |
| << DeclType; |
| hadError = true; |
| } |
| } |
| |
| void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, |
| InitListExpr *IList, |
| QualType ElemType, |
| unsigned &Index, |
| InitListExpr *StructuredList, |
| unsigned &StructuredIndex, |
| bool DirectlyDesignated) { |
| 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) { |
| // FIXME: It would be more faithful and no less correct to include an |
| // InitListExpr in the semantic form of the initializer list in this case. |
| expr = SubInitList->getInit(0); |
| } |
| // Nested aggregate initialization and C++ initialization are 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"); |
| UpdateStructuredListElement(StructuredList, StructuredIndex, expr); |
| ++Index; |
| return; |
| } |
| |
| if (SemaRef.getLangOpts().CPlusPlus || isa<InitListExpr>(expr)) { |
| // C++ [dcl.init.aggr]p2: |
| // Each member is copy-initialized from the corresponding |
| // initializer-clause. |
| |
| // FIXME: Better EqualLoc? |
| InitializationKind Kind = |
| InitializationKind::CreateCopy(expr->getBeginLoc(), SourceLocation()); |
| |
| // Vector elements can be initialized from other vectors in which case |
| // we need initialization entity with a type of a vector (and not a vector |
| // element!) initializing multiple vector elements. |
| auto TmpEntity = |
| (ElemType->isExtVectorType() && !Entity.getType()->isExtVectorType()) |
| ? InitializedEntity::InitializeTemporary(ElemType) |
| : Entity; |
| |
| InitializationSequence Seq(SemaRef, TmpEntity, 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, TmpEntity, Kind, expr); |
| if (Result.isInvalid()) |
| hadError = true; |
| |
| UpdateStructuredListElement(StructuredList, StructuredIndex, |
| Result.getAs<Expr>()); |
| } else if (!Seq) { |
| hadError = true; |
| } else if (StructuredList) { |
| UpdateStructuredListElement(StructuredList, StructuredIndex, |
| getDummyInit()); |
| } |
| ++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) { |
| // FIXME: Should we do this checking in verify-only mode? |
| if (!VerifyOnly) |
| CheckStringInit(expr, ElemType, arrayType, SemaRef); |
| if (StructuredList) |
| 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; |
| |
| // In C++20, brace elision is not permitted for a designated initializer. |
| if (DirectlyDesignated && SemaRef.getLangOpts().CPlusPlus && !hadError) { |
| if (InOverloadResolution) |
| hadError = true; |
| if (!VerifyOnly) { |
| SemaRef.Diag(expr->getBeginLoc(), |
| diag::ext_designated_init_brace_elision) |
| << expr->getSourceRange() |
| << FixItHint::CreateInsertion(expr->getBeginLoc(), "{") |
| << FixItHint::CreateInsertion( |
| SemaRef.getLocForEndOfToken(expr->getEndLoc()), "}"); |
| } |
| } |
| } else { |
| if (!VerifyOnly) { |
| // We cannot initialize this element, so let PerformCopyInitialization |
| // produce the appropriate diagnostic. We already checked that this |
| // initialization will fail. |
| ExprResult Copy = |
| SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr, |
| /*TopLevelOfInitList=*/true); |
| (void)Copy; |
| assert(Copy.isInvalid() && |
| "expected non-aggregate initialization to fail"); |
| } |
| 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->getBeginLoc(), diag::ext_complex_component_init) |
| << IList->getSourceRange(); |
| |
| // Initialize the complex number. |
| QualType elementType = DeclType->castAs<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) { |
| if (DeclType->isSizelessBuiltinType()) |
| SemaRef.Diag(IList->getBeginLoc(), |
| SemaRef.getLangOpts().CPlusPlus11 |
| ? diag::warn_cxx98_compat_empty_sizeless_initializer |
| : diag::err_empty_sizeless_initializer) |
| << DeclType << IList->getSourceRange(); |
| else |
| SemaRef.Diag(IList->getBeginLoc(), |
| 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->getBeginLoc(), diag::ext_many_braces_around_init) |
| << DeclType->isSizelessBuiltinType() << SubIList->getSourceRange(); |
| |
| CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, |
| StructuredIndex); |
| return; |
| } else if (isa<DesignatedInitExpr>(expr)) { |
| if (!VerifyOnly) |
| SemaRef.Diag(expr->getBeginLoc(), |
| diag::err_designator_for_scalar_or_sizeless_init) |
| << DeclType->isSizelessBuiltinType() << DeclType |
| << expr->getSourceRange(); |
| hadError = true; |
| ++Index; |
| ++StructuredIndex; |
| return; |
| } |
| |
| ExprResult Result; |
| if (VerifyOnly) { |
| if (SemaRef.CanPerformCopyInitialization(Entity, expr)) |
| Result = getDummyInit(); |
| else |
| Result = ExprError(); |
| } else { |
| Result = |
| SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr, |
| /*TopLevelOfInitList=*/true); |
| } |
| |
| Expr *ResultExpr = nullptr; |
| |
| if (Result.isInvalid()) |
| hadError = true; // types weren't compatible. |
| else { |
| ResultExpr = Result.getAs<Expr>(); |
| |
| if (ResultExpr != expr && !VerifyOnly) { |
| // The type was promoted, update initializer list. |
| // FIXME: Why are we updating the syntactic init list? |
| IList->setInit(Index, ResultExpr); |
| } |
| } |
| 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->getBeginLoc(), |
| 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->getBeginLoc(), diag::err_init_non_aggr_init_list) |
| << DeclType << IList->getSourceRange(); |
| hadError = true; |
| ++Index; |
| ++StructuredIndex; |
| return; |
| } |
| |
| ExprResult Result; |
| if (VerifyOnly) { |
| if (SemaRef.CanPerformCopyInitialization(Entity,expr)) |
| Result = getDummyInit(); |
| else |
| Result = ExprError(); |
| } else { |
| Result = |
| SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr, |
| /*TopLevelOfInitList=*/true); |
| } |
| |
| if (Result.isInvalid()) |
| hadError = true; |
| |
| expr = Result.getAs<Expr>(); |
| // FIXME: Why are we updating the syntactic init list? |
| if (!VerifyOnly && expr) |
| IList->setInit(Index, expr); |
| |
| 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->castAs<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. |
| CheckEmptyInitializable( |
| InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity), |
| IList->getEndLoc()); |
| 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()) { |
| ExprResult Result; |
| if (VerifyOnly) { |
| if (SemaRef.CanPerformCopyInitialization(Entity, Init)) |
| Result = getDummyInit(); |
| else |
| Result = ExprError(); |
| } else { |
| Result = |
| SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init, |
| /*TopLevelOfInitList=*/true); |
| } |
| |
| Expr *ResultExpr = nullptr; |
| if (Result.isInvalid()) |
| hadError = true; // types weren't compatible. |
| else { |
| ResultExpr = Result.getAs<Expr>(); |
| |
| if (ResultExpr != Init && !VerifyOnly) { |
| // The type was promoted, update initializer list. |
| // FIXME: Why are we updating the syntactic init list? |
| IList->setInit(Index, ResultExpr); |
| } |
| } |
| 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()) { |
| CheckEmptyInitializable(ElementEntity, IList->getEndLoc()); |
| 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()->castAs<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->getBeginLoc(), |
| 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->getBeginLoc(), |
| 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->castAs<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->getBeginLoc(), |
| diag::err_vector_incorrect_num_initializers) |
| << (numEltsInit < maxElements) << maxElements << numEltsInit; |
| hadError = true; |
| } |
| } |
| |
| /// Check if the type of a class element has an accessible destructor, and marks |
| /// it referenced. Returns true if we shouldn't form a reference to the |
| /// destructor. |
| /// |
| /// Aggregate initialization requires a class element's destructor be |
| /// accessible per 11.6.1 [dcl.init.aggr]: |
| /// |
| /// The destructor for each element of class type is potentially invoked |
| /// (15.4 [class.dtor]) from the context where the aggregate initialization |
| /// occurs. |
| static bool checkDestructorReference(QualType ElementType, SourceLocation Loc, |
| Sema &SemaRef) { |
| auto *CXXRD = ElementType->getAsCXXRecordDecl(); |
| if (!CXXRD) |
| return false; |
| |
| CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD); |
| SemaRef.CheckDestructorAccess(Loc, Destructor, |
| SemaRef.PDiag(diag::err_access_dtor_temp) |
| << ElementType); |
| SemaRef.MarkFunctionReferenced(Loc, Destructor); |
| return SemaRef.DiagnoseUseOfDecl(Destructor, Loc); |
| } |
| |
| 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); |
| |
| if (!VerifyOnly) { |
| if (checkDestructorReference(arrayType->getElementType(), |
| IList->getEndLoc(), SemaRef)) { |
| hadError = true; |
| return; |
| } |
| } |
| |
| // 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. |
| // FIXME: Should we do these checks in verify-only mode too? |
| if (!VerifyOnly) |
| CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef); |
| if (StructuredList) { |
| 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()->getBeginLoc(), |
| 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->getBeginLoc(), diag::ext_typecheck_zero_array_size); |
| } |
| |
| DeclType = SemaRef.Context.getConstantArrayType( |
| elementType, maxElements, nullptr, ArrayType::Normal, 0); |
| } |
| if (!hadError) { |
| // 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. |
| if ((maxElementsKnown && elementIndex < maxElements) || |
| Entity.isVariableLengthArrayNew()) |
| CheckEmptyInitializable( |
| InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity), |
| IList->getEndLoc()); |
| } |
| } |
| |
| 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->getBeginLoc(), FlexArrayDiag) |
| << InitExpr->getBeginLoc(); |
| 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->castAs<RecordType>()->getDecl(); |
| |
| // If the record is invalid, some of it's members are invalid. To avoid |
| // confusion, we forgo checking the initializer 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->castAs<RecordType>()->getDecl(); |
| |
| if (!VerifyOnly) |
| for (FieldDecl *FD : RD->fields()) { |
| QualType ET = SemaRef.Context.getBaseElementType(FD->getType()); |
| if (checkDestructorReference(ET, IList->getEndLoc(), SemaRef)) { |
| hadError = true; |
| return; |
| } |
| } |
| |
| // If there's a default initializer, use it. |
| if (isa<CXXRecordDecl>(RD) && |
| cast<CXXRecordDecl>(RD)->hasInClassInitializer()) { |
| if (!StructuredList) |
| 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()) { |
| CheckEmptyInitializable( |
| InitializedEntity::InitializeMember(*Field, &Entity), |
| IList->getEndLoc()); |
| if (StructuredList) |
| 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; |
| |
| // 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; |
| |
| SourceLocation InitLoc = Init ? Init->getBeginLoc() : IList->getEndLoc(); |
| InitializedEntity BaseEntity = InitializedEntity::InitializeBase( |
| SemaRef.Context, &Base, false, &Entity); |
| if (Init) { |
| CheckSubElementType(BaseEntity, IList, Base.getType(), Index, |
| StructuredList, StructuredIndex); |
| InitializedSomething = true; |
| } else { |
| CheckEmptyInitializable(BaseEntity, InitLoc); |
| } |
| |
| if (!VerifyOnly) |
| if (checkDestructorReference(Base.getType(), InitLoc, SemaRef)) { |
| hadError = true; |
| return; |
| } |
| } |
| |
| // 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->castAs<RecordType>()->getDecl(); |
| RecordDecl::field_iterator FieldEnd = RD->field_end(); |
| bool CheckForMissingFields = |
| !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); |
| bool HasDesignatedInit = false; |
| |
| while (Index < IList->getNumInits()) { |
| Expr *Init = IList->getInit(Index); |
| SourceLocation InitLoc = Init->getBeginLoc(); |
| |
| 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; |
| |
| HasDesignatedInit = true; |
| |
| // 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; |
| else if (!VerifyOnly) { |
| // Find the field named by the designated initializer. |
| RecordDecl::field_iterator F = RD->field_begin(); |
| while (std::next(F) != Field) |
| ++F; |
| QualType ET = SemaRef.Context.getBaseElementType(F->getType()); |
| if (checkDestructorReference(ET, InitLoc, SemaRef)) { |
| hadError = true; |
| return; |
| } |
| } |
| |
| 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)->getBeginLoc()); |
| if (InvalidUse) { |
| ++Index; |
| ++Field; |
| hadError = true; |
| continue; |
| } |
| |
| if (!VerifyOnly) { |
| QualType ET = SemaRef.Context.getBaseElementType(Field->getType()); |
| if (checkDestructorReference(ET, InitLoc, SemaRef)) { |
| hadError = true; |
| return; |
| } |
| } |
| |
| InitializedEntity MemberEntity = |
| InitializedEntity::InitializeMember(*Field, &Entity); |
| CheckSubElementType(MemberEntity, IList, Field->getType(), Index, |
| StructuredList, StructuredIndex); |
| InitializedSomething = true; |
| |
| if (DeclType->isUnionType() && StructuredList) { |
| // 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 we're not |
| // building a structured list. (If we are, we'll check this later.) |
| if (!StructuredList && Field != FieldEnd && !DeclType->isUnionType() && |
| !Field->getType()->isIncompleteArrayType()) { |
| for (; Field != FieldEnd && !hadError; ++Field) { |
| if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer()) |
| CheckEmptyInitializable( |
| InitializedEntity::InitializeMember(*Field, &Entity), |
| IList->getEndLoc()); |
| } |
| } |
| |
| // Check that the types of the remaining fields have accessible destructors. |
| if (!VerifyOnly) { |
| // If the initializer expression has a designated initializer, check the |
| // elements for which a designated initializer is not provided too. |
| RecordDecl::field_iterator I = HasDesignatedInit ? RD->field_begin() |
| : Field; |
| for (RecordDecl::field_iterator E = RD->field_end(); I != E; ++I) { |
| QualType ET = SemaRef.Context.getBaseElementType(I->getType()); |
| if (checkDestructorReference(ET, IList->getEndLoc(), SemaRef)) { |
| hadError = true; |
| return; |
| } |
| } |
| } |
| |
| 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); |
| } |
| |
| /// 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 final : 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); |
| } |
| |
| std::unique_ptr<CorrectionCandidateCallback> clone() override { |
| return std::make_unique<FieldInitializerValidatorCCC>(*this); |
| } |
| |
| private: |
| RecordDecl *Record; |
| }; |
| |
| } // end anonymous namespace |
| |
| /// 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. On input, this is expected to be |
| /// the next field that would be initialized in the absence of designation, |
| /// if the complete object being initialized is a struct. |
| /// |
| /// @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()) { |
| // C++20 designated initialization can result in direct-list-initialization |
| // of the designated subobject. This is the only way that we can end up |
| // performing direct initialization as part of aggregate initialization, so |
| // it needs special handling. |
| if (DIE->isDirectInit()) { |
| Expr *Init = DIE->getInit(); |
| assert(isa<InitListExpr>(Init) && |
| "designator result in direct non-list initialization?"); |
| InitializationKind Kind = InitializationKind::CreateDirectList( |
| DIE->getBeginLoc(), Init->getBeginLoc(), Init->getEndLoc()); |
| InitializationSequence Seq(SemaRef, Entity, Kind, Init, |
| /*TopLevelOfInitList*/ true); |
| if (StructuredList) { |
| ExprResult Result = VerifyOnly |
| ? getDummyInit() |
| : Seq.Perform(SemaRef, Entity, Kind, Init); |
| UpdateStructuredListElement(StructuredList, StructuredIndex, |
| Result.get()); |
| } |
| ++Index; |
| return !Seq; |
| } |
| |
| // 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, /*DirectlyDesignated=*/true); |
| |
| // 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 (IsFirstDesignator ? FullyStructuredList : StructuredList) { |
| // Determine the structural initializer list that corresponds to the |
| // current subobject. |
| if (IsFirstDesignator) |
| StructuredList = FullyStructuredList; |
| 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->getBeginLoc(), DIE->getEndLoc())); |
| else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit)) |
| StructuredList = Result; |
| else { |
| // 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 == 1 and xs[0].b == 3, since the second, |
| // designated initializer re-initializes only its current object |
| // subobject [0].b. |
| diagnoseInitOverride(ExistingInit, |
| SourceRange(D->getBeginLoc(), DIE->getEndLoc()), |
| /*FullyOverwritten=*/false); |
| |
| if (!VerifyOnly) { |
| if (DesignatedInitUpdateExpr *E = |
| dyn_cast<DesignatedInitUpdateExpr>(ExistingInit)) |
| StructuredList = E->getUpdater(); |
| else { |
| DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context) |
| DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(), |
| ExistingInit, DIE->getEndLoc()); |
| StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE); |
| StructuredList = DIUE->getUpdater(); |
| } |
| } else { |
| // We don't need to track the structured representation of a |
| // designated init update of an already-fully-initialized object in |
| // verify-only mode. The only reason we would need the structure is |
| // to determine where the uninitialized "holes" are, and in this |
| // case, we know there aren't any and we can't introduce any. |
| StructuredList = nullptr; |
| } |
| } |
| } |
| } |
| |
| 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. |
| FieldInitializerValidatorCCC CCC(RT->getDecl()); |
| if (TypoCorrection Corrected = SemaRef.CorrectTypo( |
| DeclarationNameInfo(FieldName, D->getFieldLoc()), |
| Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, CCC, |
| 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 NumBases = 0; |
| if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl())) |
| NumBases = CXXRD->getNumBases(); |
| |
| unsigned FieldIndex = NumBases; |
| |
| 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 (StructuredList) { |
| 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. |
| diagnoseInitOverride( |
| ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc())); |
| } |
| |
| // 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; |
| } |
| |
| // C++20 [dcl.init.list]p3: |
| // The ordered identifiers in the designators of the designated- |
| // initializer-list shall form a subsequence of the ordered identifiers |
| // in the direct non-static data members of T. |
| // |
| // Note that this is not a condition on forming the aggregate |
| // initialization, only on actually performing initialization, |
| // so it is not checked in VerifyOnly mode. |
| // |
| // FIXME: This is the only reordering diagnostic we produce, and it only |
| // catches cases where we have a top-level field designator that jumps |
| // backwards. This is the only such case that is reachable in an |
| // otherwise-valid C++20 program, so is the only case that's required for |
| // conformance, but for consistency, we should diagnose all the other |
| // cases where a designator takes us backwards too. |
| if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus && |
| NextField && |
| (*NextField == RT->getDecl()->field_end() || |
| (*NextField)->getFieldIndex() > Field->getFieldIndex() + 1)) { |
| // Find the field that we just initialized. |
| FieldDecl *PrevField = nullptr; |
| for (auto FI = RT->getDecl()->field_begin(); |
| FI != RT->getDecl()->field_end(); ++FI) { |
| if (FI->isUnnamedBitfield()) |
| continue; |
| if (*NextField != RT->getDecl()->field_end() && |
| declaresSameEntity(*FI, **NextField)) |
| break; |
| PrevField = *FI; |
| } |
| |
| if (PrevField && |
| PrevField->getFieldIndex() > KnownField->getFieldIndex()) { |
| SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered) |
| << KnownField << PrevField << DIE->getSourceRange(); |
| |
| unsigned OldIndex = NumBases + PrevField->getFieldIndex(); |
| if (StructuredList && OldIndex <= StructuredList->getNumInits()) { |
| if (Expr *PrevInit = StructuredList->getInit(OldIndex)) { |
| SemaRef.Diag(PrevInit->getBeginLoc(), |
| diag::note_previous_field_init) |
| << PrevField << PrevInit->getSourceRange(); |
| } |
| } |
| } |
| } |
| |
| |
| // Update the designator with the field declaration. |
| if (!VerifyOnly) |
| D->setField(*Field); |
| |
| // Make sure that our non-designated initializer list has space |
| // for a subobject corresponding to this field. |
| if (StructuredList && 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). |