diff options
author | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
commit | 9cedb8bb69b89b0f0c529937247a6a80cabdbaec (patch) | |
tree | c978f0e9ec1ab92dc8123783f30b08a7fd1e2a39 /contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp | |
parent | 03fdc2934eb61c44c049a02b02aa974cfdd8a0eb (diff) | |
download | FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.zip FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.tar.gz |
MFC 261991:
Upgrade our copy of llvm/clang to 3.4 release. This version supports
all of the features in the current working draft of the upcoming C++
standard, provisionally named C++1y.
The code generator's performance is greatly increased, and the loop
auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The
PowerPC backend has made several major improvements to code generation
quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ
backends have all seen major feature work.
Release notes for llvm and clang can be found here:
<http://llvm.org/releases/3.4/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>
MFC 262121 (by emaste):
Update lldb for clang/llvm 3.4 import
This commit largely restores the lldb source to the upstream r196259
snapshot with the addition of threaded inferior support and a few bug
fixes.
Specific upstream lldb revisions restored include:
SVN git
181387 779e6ac
181703 7bef4e2
182099 b31044e
182650 f2dcf35
182683 0d91b80
183862 15c1774
183929 99447a6
184177 0b2934b
184948 4dc3761
184954 007e7bc
186990 eebd175
Sponsored by: DARPA, AFRL
MFC 262186 (by emaste):
Fix mismerge in r262121
A break statement was lost in the merge. The error had no functional
impact, but restore it to reduce the diff against upstream.
MFC 262303:
Pull in r197521 from upstream clang trunk (by rdivacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Requested by: jhibbits
MFC 262611:
Pull in r196874 from upstream llvm trunk:
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don't need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won't conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
This should help fix assertions occurring with ports-mgmt/tinderbox,
when it is using jails, and sometimes invalidates clang's current
working directory.
Reported by: decke
MFC 262809:
Pull in r203007 from upstream clang trunk:
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
(Please note that is an LLVM PR identifier, not a FreeBSD one.)
This should fix Firefox and/or libxul crashes (due to problems with
regparm/stdcall calling conventions) on i386.
Reported by: multiple users on freebsd-current
PR: bin/187103
MFC 263048:
Repair recognition of "CC" as an alias for the C++ compiler, since it
was silently broken by upstream for a Windows-specific use-case.
Apparently some versions of CMake still rely on this archaic feature...
Reported by: rakuco
MFC 263049:
Garbage collect the old way of adding the libstdc++ include directories
in clang's InitHeaderSearch.cpp. This has been superseded by David
Chisnall's commit in r255321.
Moreover, if libc++ is used, the libstdc++ include directories should
not be in the search path at all. These directories are now only used
if you pass -stdlib=libstdc++.
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp | 1166 |
1 files changed, 830 insertions, 336 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp index a632f02..034c1b6 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp @@ -32,53 +32,99 @@ using namespace clang; // Sema Initialization Checking //===----------------------------------------------------------------------===// -static Expr *IsStringInit(Expr *Init, const ArrayType *AT, - ASTContext &Context) { +/// \brief Check whether T is compatible with a wide character type (wchar_t, +/// char16_t or char32_t). +static bool IsWideCharCompatible(QualType T, ASTContext &Context) { + if (Context.typesAreCompatible(Context.getWideCharType(), T)) + return true; + if (Context.getLangOpts().CPlusPlus || Context.getLangOpts().C11) { + return Context.typesAreCompatible(Context.Char16Ty, T) || + Context.typesAreCompatible(Context.Char32Ty, T); + } + return false; +} + +enum StringInitFailureKind { + SIF_None, + SIF_NarrowStringIntoWideChar, + SIF_WideStringIntoChar, + SIF_IncompatWideStringIntoWideChar, + SIF_Other +}; + +/// \brief Check whether the array of type AT can be initialized by the Init +/// expression by means of string initialization. Returns SIF_None if so, +/// otherwise returns a StringInitFailureKind that describes why the +/// initialization would not work. +static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, + ASTContext &Context) { if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT)) - return 0; + 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 Init; + return SIF_None; // Otherwise we can only handle string literals. StringLiteral *SL = dyn_cast<StringLiteral>(Init); - if (SL == 0) return 0; + if (SL == 0) + return SIF_Other; - QualType ElemTy = Context.getCanonicalType(AT->getElementType()); + const QualType ElemTy = + Context.getCanonicalType(AT->getElementType()).getUnqualifiedType(); switch (SL->getKind()) { case StringLiteral::Ascii: case StringLiteral::UTF8: // char array can be initialized with a narrow string. // Only allow char x[] = "foo"; not char x[] = L"foo"; - return ElemTy->isCharType() ? Init : 0; + if (ElemTy->isCharType()) + return SIF_None; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_NarrowStringIntoWideChar; + return SIF_Other; + // C99 6.7.8p15 (with correction from DR343), or C11 6.7.9p15: + // "An array with element type compatible with a qualified or unqualified + // version of wchar_t, char16_t, or char32_t may be initialized by a wide + // string literal with the corresponding encoding prefix (L, u, or U, + // respectively), optionally enclosed in braces. case StringLiteral::UTF16: - return ElemTy->isChar16Type() ? Init : 0; + if (Context.typesAreCompatible(Context.Char16Ty, ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; case StringLiteral::UTF32: - return ElemTy->isChar32Type() ? Init : 0; + if (Context.typesAreCompatible(Context.Char32Ty, ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; case StringLiteral::Wide: - // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with - // correction from DR343): "An array with element type compatible with a - // qualified or unqualified version of wchar_t may be initialized by a wide - // string literal, optionally enclosed in braces." - if (Context.typesAreCompatible(Context.getWCharType(), - ElemTy.getUnqualifiedType())) - return Init; - - return 0; + if (Context.typesAreCompatible(Context.getWideCharType(), ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; } llvm_unreachable("missed a StringLiteral kind?"); } -static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) { +static StringInitFailureKind IsStringInit(Expr *init, QualType declType, + ASTContext &Context) { const ArrayType *arrayType = Context.getAsArrayType(declType); - if (!arrayType) return 0; - + if (!arrayType) + return SIF_Other; return IsStringInit(init, arrayType, Context); } @@ -190,7 +236,6 @@ class InitListChecker { Sema &SemaRef; bool hadError; bool VerifyOnly; // no diagnostics, no structure building - bool AllowBraceElision; llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic; InitListExpr *FullyStructuredList; @@ -200,8 +245,7 @@ class InitListChecker { unsigned &StructuredIndex); void CheckExplicitInitList(const InitializedEntity &Entity, InitListExpr *IList, QualType &T, - unsigned &Index, InitListExpr *StructuredList, - unsigned &StructuredIndex, + InitListExpr *StructuredList, bool TopLevelObject = false); void CheckListElementTypes(const InitializedEntity &Entity, InitListExpr *IList, QualType &DeclType, @@ -281,8 +325,7 @@ class InitListChecker { public: InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T, bool VerifyOnly, - bool AllowBraceElision); + InitListExpr *IL, QualType &T, bool VerifyOnly); bool HadError() { return hadError; } // @brief Retrieves the fully-structured initializer list used for @@ -513,16 +556,13 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, - bool VerifyOnly, bool AllowBraceElision) - : SemaRef(S), VerifyOnly(VerifyOnly), AllowBraceElision(AllowBraceElision) { + bool VerifyOnly) + : SemaRef(S), VerifyOnly(VerifyOnly) { hadError = false; - unsigned newIndex = 0; - unsigned newStructuredIndex = 0; - FullyStructuredList - = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange()); - CheckExplicitInitList(Entity, IL, T, newIndex, - FullyStructuredList, newStructuredIndex, + FullyStructuredList = + getStructuredSubobjectInit(IL, 0, T, 0, 0, IL->getSourceRange()); + CheckExplicitInitList(Entity, IL, T, FullyStructuredList, /*TopLevelObject=*/true); if (!hadError && !VerifyOnly) { @@ -559,6 +599,12 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { return InitializableMembers - structDecl->hasFlexibleArrayMember(); } +/// 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, @@ -599,10 +645,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, StructuredSubobjectInitList, StructuredSubobjectInitIndex); - if (VerifyOnly) { - if (!AllowBraceElision && (T->isArrayType() || T->isRecordType())) - hadError = true; - } else { + if (!VerifyOnly) { StructuredSubobjectInitList->setType(T); unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1); @@ -617,8 +660,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, // Complain about missing braces. if (T->isArrayType() || T->isRecordType()) { SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), - AllowBraceElision ? diag::warn_missing_braces : - diag::err_missing_braces) + diag::warn_missing_braces) << StructuredSubobjectInitList->getSourceRange() << FixItHint::CreateInsertion( StructuredSubobjectInitList->getLocStart(), "{") @@ -626,23 +668,26 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, SemaRef.PP.getLocForEndOfToken( StructuredSubobjectInitList->getLocEnd()), "}"); - if (!AllowBraceElision) - hadError = true; } } } +/// 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, - unsigned &Index, InitListExpr *StructuredList, - unsigned &StructuredIndex, bool TopLevelObject) { assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); if (!VerifyOnly) { SyntacticToSemantic[IList] = StructuredList; StructuredList->setSyntacticForm(IList); } + + unsigned Index = 0, StructuredIndex = 0; CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, Index, StructuredList, StructuredIndex, TopLevelObject); if (!VerifyOnly) { @@ -667,7 +712,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, } if (StructuredIndex == 1 && - IsStringInit(StructuredList->getInit(0), T, SemaRef.Context)) { + IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) == + SIF_None) { unsigned DK = diag::warn_excess_initializers_in_char_array_initializer; if (SemaRef.getLangOpts().CPlusPlus) { DK = diag::err_excess_initializers_in_char_array_initializer; @@ -781,14 +827,12 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) { if (!ElemType->isRecordType() || ElemType->isAggregateType()) { - unsigned newIndex = 0; - unsigned newStructuredIndex = 0; - InitListExpr *newStructuredList + InitListExpr *InnerStructuredList = getStructuredSubobjectInit(IList, Index, ElemType, StructuredList, StructuredIndex, SubInitList->getSourceRange()); - CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex, - newStructuredList, newStructuredIndex); + CheckExplicitInitList(Entity, SubInitList, ElemType, + InnerStructuredList); ++StructuredIndex; ++Index; return; @@ -811,10 +855,10 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // array member. There's nothing we can do with the completed // type here, though. - if (Expr *Str = IsStringInit(expr, arrayType, SemaRef.Context)) { + if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) { if (!VerifyOnly) { - CheckStringInit(Str, ElemType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + CheckStringInit(expr, ElemType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); } ++Index; return; @@ -862,7 +906,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, if ((ElemType->isRecordType() || ElemType->isVectorType()) && SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes, !VerifyOnly) - == Sema::Compatible) { + != Sema::Incompatible) { if (ExprRes.isInvalid()) hadError = true; else { @@ -1194,16 +1238,17 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, // Check for the special-case of initializing an array with a string. if (Index < IList->getNumInits()) { - if (Expr *Str = IsStringInit(IList->getInit(Index), arrayType, - SemaRef.Context)) { + if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) == + SIF_None) { // We place the string literal directly into the resulting // initializer list. This is the only place where the structure // of the structured initializer list doesn't match exactly, // because doing so would involve allocating one character // constant for each string. if (!VerifyOnly) { - CheckStringInit(Str, DeclType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, + IList->getInit(Index)); StructuredList->resizeInits(SemaRef.Context, StructuredIndex); } ++Index; @@ -1773,22 +1818,15 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Name lookup didn't find anything. Determine whether this // was a typo for another field name. FieldInitializerValidatorCCC Validator(RT->getDecl()); - TypoCorrection Corrected = SemaRef.CorrectTypo( - DeclarationNameInfo(FieldName, D->getFieldLoc()), - Sema::LookupMemberName, /*Scope=*/0, /*SS=*/0, Validator, - RT->getDecl()); - if (Corrected) { - std::string CorrectedStr( - Corrected.getAsString(SemaRef.getLangOpts())); - std::string CorrectedQuotedStr( - Corrected.getQuoted(SemaRef.getLangOpts())); + if (TypoCorrection Corrected = SemaRef.CorrectTypo( + DeclarationNameInfo(FieldName, D->getFieldLoc()), + Sema::LookupMemberName, /*Scope=*/ 0, /*SS=*/ 0, Validator, + RT->getDecl())) { + SemaRef.diagnoseTypo( + Corrected, + SemaRef.PDiag(diag::err_field_designator_unknown_suggest) + << FieldName << CurrentObjectType); ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>(); - SemaRef.Diag(D->getFieldLoc(), - diag::err_field_designator_unknown_suggest) - << FieldName << CurrentObjectType << CorrectedQuotedStr - << FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr); - SemaRef.Diag(ReplacementField->getLocation(), - diag::note_previous_decl) << CorrectedQuotedStr; hadError = true; } else { SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) @@ -1830,8 +1868,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // the initializer list. if (RT->getDecl()->isUnion()) { FieldIndex = 0; - if (!VerifyOnly) + if (!VerifyOnly) { + FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion(); + if (CurrentField && CurrentField != *Field) { + assert(StructuredList->getNumInits() == 1 + && "A union should never have more than one initializer!"); + + // we're about to throw away an initializer, emit warning + SemaRef.Diag(D->getFieldLoc(), + diag::warn_initializer_overrides) + << D->getSourceRange(); + Expr *ExistingInit = StructuredList->getInit(0); + SemaRef.Diag(ExistingInit->getLocStart(), + diag::note_previous_initializer) + << /*FIXME:has side effects=*/0 + << ExistingInit->getSourceRange(); + + // remove existing initializer + StructuredList->resizeInits(SemaRef.Context, 0); + StructuredList->setInitializedFieldInUnion(0); + } + StructuredList->setInitializedFieldInUnion(*Field); + } } // Make sure we can use this declaration. @@ -2039,6 +2098,64 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, DesignatedEndIndex.setIsUnsigned(true); } + if (!VerifyOnly && StructuredList->isStringLiteralInit()) { + // We're modifying a string literal init; we have to decompose the string + // so we can modify the individual characters. + ASTContext &Context = SemaRef.Context; + Expr *SubExpr = StructuredList->getInit(0)->IgnoreParens(); + + // Compute the character type + QualType CharTy = AT->getElementType(); + + // Compute the type of the integer literals. + QualType PromotedCharTy = CharTy; + if (CharTy->isPromotableIntegerType()) + PromotedCharTy = Context.getPromotedIntegerType(CharTy); + unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy); + + if (StringLiteral *SL = dyn_cast<StringLiteral>(SubExpr)) { + // Get the length of the string. + uint64_t StrLen = SL->getLength(); + if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen)) + StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue(); + StructuredList->resizeInits(Context, StrLen); + + // Build a literal for each character in the string, and put them into + // the init list. + for (unsigned i = 0, e = StrLen; i != e; ++i) { + llvm::APInt CodeUnit(PromotedCharTyWidth, SL->getCodeUnit(i)); + Expr *Init = new (Context) IntegerLiteral( + Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc()); + if (CharTy != PromotedCharTy) + Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast, + Init, 0, VK_RValue); + StructuredList->updateInit(Context, i, Init); + } + } else { + ObjCEncodeExpr *E = cast<ObjCEncodeExpr>(SubExpr); + std::string Str; + Context.getObjCEncodingForType(E->getEncodedType(), Str); + + // Get the length of the string. + uint64_t StrLen = Str.size(); + if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen)) + StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue(); + StructuredList->resizeInits(Context, StrLen); + + // Build a literal for each character in the string, and put them into + // the init list. + for (unsigned i = 0, e = StrLen; i != e; ++i) { + llvm::APInt CodeUnit(PromotedCharTyWidth, Str[i]); + Expr *Init = new (Context) IntegerLiteral( + Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc()); + if (CharTy != PromotedCharTy) + Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast, + Init, 0, VK_RValue); + StructuredList->updateInit(Context, i, Init); + } + } + } + // Make sure that our non-designated initializer list has space // for a subobject corresponding to this array element. if (!VerifyOnly && @@ -2361,12 +2478,13 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, } } -InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, - CXXBaseSpecifier *Base, - bool IsInheritedVirtualBase) -{ +InitializedEntity +InitializedEntity::InitializeBase(ASTContext &Context, + const CXXBaseSpecifier *Base, + bool IsInheritedVirtualBase) { InitializedEntity Result; Result.Kind = EK_Base; + Result.Parent = 0; Result.Base = reinterpret_cast<uintptr_t>(Base); if (IsInheritedVirtualBase) Result.Base |= 0x01; @@ -2377,7 +2495,8 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, DeclarationName InitializedEntity::getName() const { switch (getKind()) { - case EK_Parameter: { + case EK_Parameter: + case EK_Parameter_CF_Audited: { ParmVarDecl *D = reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1); return (D ? D->getDeclName() : DeclarationName()); } @@ -2387,7 +2506,7 @@ DeclarationName InitializedEntity::getName() const { return VariableOrMember->getDeclName(); case EK_LambdaCapture: - return Capture.Var->getDeclName(); + return DeclarationName(Capture.VarID); case EK_Result: case EK_Exception: @@ -2400,6 +2519,7 @@ DeclarationName InitializedEntity::getName() const { case EK_ComplexElement: case EK_BlockElement: case EK_CompoundLiteralInit: + case EK_RelatedResult: return DeclarationName(); } @@ -2413,6 +2533,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { return VariableOrMember; case EK_Parameter: + case EK_Parameter_CF_Audited: return reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1); case EK_Result: @@ -2427,6 +2548,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_BlockElement: case EK_LambdaCapture: case EK_CompoundLiteralInit: + case EK_RelatedResult: return 0; } @@ -2441,6 +2563,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Variable: case EK_Parameter: + case EK_Parameter_CF_Audited: case EK_Member: case EK_New: case EK_Temporary: @@ -2452,12 +2575,57 @@ bool InitializedEntity::allowsNRVO() const { case EK_ComplexElement: case EK_BlockElement: case EK_LambdaCapture: + case EK_RelatedResult: break; } return false; } +unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { + assert(getParent() != this); + unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0; + for (unsigned I = 0; I != Depth; ++I) + OS << "`-"; + + switch (getKind()) { + case EK_Variable: OS << "Variable"; break; + case EK_Parameter: OS << "Parameter"; break; + case EK_Parameter_CF_Audited: OS << "CF audited function Parameter"; + break; + case EK_Result: OS << "Result"; break; + case EK_Exception: OS << "Exception"; break; + case EK_Member: OS << "Member"; break; + case EK_New: OS << "New"; break; + case EK_Temporary: OS << "Temporary"; break; + case EK_CompoundLiteralInit: OS << "CompoundLiteral";break; + case EK_RelatedResult: OS << "RelatedResult"; break; + case EK_Base: OS << "Base"; break; + case EK_Delegating: OS << "Delegating"; break; + case EK_ArrayElement: OS << "ArrayElement " << Index; break; + case EK_VectorElement: OS << "VectorElement " << Index; break; + case EK_ComplexElement: OS << "ComplexElement " << Index; break; + case EK_BlockElement: OS << "Block"; break; + case EK_LambdaCapture: + OS << "LambdaCapture "; + OS << DeclarationName(Capture.VarID); + break; + } + + if (Decl *D = getDecl()) { + OS << " "; + cast<NamedDecl>(D)->printQualifiedName(OS); + } + + OS << " '" << getType().getAsString() << "'\n"; + + return Depth + 1; +} + +void InitializedEntity::dump() const { + dumpImpl(llvm::errs()); +} + //===----------------------------------------------------------------------===// // Initialization sequence //===----------------------------------------------------------------------===// @@ -2496,6 +2664,7 @@ void InitializationSequence::Step::Destroy() { break; case SK_ConversionSequence: + case SK_ConversionSequenceNoNarrowing: delete ICS; } } @@ -2512,6 +2681,10 @@ bool InitializationSequence::isAmbiguous() const { case FK_TooManyInitsForReference: case FK_ArrayNeedsInitList: case FK_ArrayNeedsInitListOrStringLiteral: + case FK_ArrayNeedsInitListOrWideStringLiteral: + case FK_NarrowStringIntoWideCharArray: + case FK_WideStringIntoCharArray: + case FK_IncompatWideStringIntoWideChar: case FK_AddressOfOverloadFailed: // FIXME: Could do better case FK_NonConstLValueReferenceBindingToTemporary: case FK_NonConstLValueReferenceBindingToUnrelated: @@ -2530,7 +2703,6 @@ bool InitializationSequence::isAmbiguous() const { case FK_ListInitializationFailed: case FK_VariableLengthArrayHasInitializer: case FK_PlaceholderType: - case FK_InitListElementCopyFailure: case FK_ExplicitConstructor: return false; @@ -2632,10 +2804,11 @@ void InitializationSequence::AddLValueToRValueStep(QualType Ty) { } void InitializationSequence::AddConversionSequenceStep( - const ImplicitConversionSequence &ICS, - QualType T) { + const ImplicitConversionSequence &ICS, QualType T, + bool TopLevelOfInitList) { Step S; - S.Kind = SK_ConversionSequence; + S.Kind = TopLevelOfInitList ? SK_ConversionSequenceNoNarrowing + : SK_ConversionSequence; S.Type = T; S.ICS = new ImplicitConversionSequence(ICS); Steps.push_back(S); @@ -2777,7 +2950,7 @@ static void MaybeProduceObjCObject(Sema &S, /// When initializing a parameter, produce the value if it's marked /// __attribute__((ns_consumed)). - if (Entity.getKind() == InitializedEntity::EK_Parameter) { + if (Entity.isParameterKind()) { if (!Entity.isParameterConsumed()) return; @@ -2797,6 +2970,12 @@ static void MaybeProduceObjCObject(Sema &S, } } +static void TryListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence); + /// \brief When initializing from init list via constructor, handle /// initialization of an object of type std::initializer_list<T>. /// @@ -2810,25 +2989,23 @@ static bool TryInitializerListConstruction(Sema &S, if (!S.isStdInitializerList(DestType, &E)) return false; - // Check that each individual element can be copy-constructed. But since we - // have no place to store further information, we'll recalculate everything - // later. - InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary( - S.Context.getConstantArrayType(E, - llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), - List->getNumInits()), - ArrayType::Normal, 0)); - InitializedEntity Element = InitializedEntity::InitializeElement(S.Context, - 0, HiddenArray); - for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) { - Element.setElementIndex(i); - if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) { - Sequence.SetFailed( - InitializationSequence::FK_InitListElementCopyFailure); - return true; - } + if (S.RequireCompleteType(List->getExprLoc(), E, 0)) { + Sequence.setIncompleteTypeFailure(E); + return true; } - Sequence.AddStdInitializerListConstructionStep(DestType); + + // Try initializing a temporary array from the init list. + QualType ArrayType = S.Context.getConstantArrayType( + E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), + List->getNumInits()), + clang::ArrayType::Normal, 0); + InitializedEntity HiddenArray = + InitializedEntity::InitializeTemporary(ArrayType); + InitializationKind Kind = + InitializationKind::CreateDirectList(List->getExprLoc()); + TryListInitialization(S, HiddenArray, Kind, List, Sequence); + if (Sequence) + Sequence.AddStdInitializerListConstructionStep(DestType); return true; } @@ -2857,9 +3034,19 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, else { Constructor = cast<CXXConstructorDecl>(D); - // If we're performing copy initialization using a copy constructor, we - // suppress user-defined conversions on the arguments. We do the same for - // move constructors. + // C++11 [over.best.ics]p4: + // However, when considering the argument of a constructor or + // user-defined conversion function that is a candidate: + // -- by 13.3.1.3 when invoked for the copying/moving of a temporary + // in the second step of a class copy-initialization, + // -- by 13.3.1.7 when passing the initializer list as a single + // argument or when the initializer list has exactly one elementand + // a conversion to some class X or reference to (possibly + // cv-qualified) X is considered for the first parameter of a + // constructor of X, or + // -- by 13.3.1.4, 13.3.1.5, or 13.3.1.6 in all cases, + // only standard conversion sequences and ellipsis conversion sequences + // are considered. if ((CopyInitializing || (InitListSyntax && Args.size() == 1)) && Constructor->isCopyOrMoveConstructor()) SuppressUserConversions = true; @@ -3058,19 +3245,12 @@ static void TryValueInitialization(Sema &S, InitializationSequence &Sequence, InitListExpr *InitList = 0); -static void TryListInitialization(Sema &S, - const InitializedEntity &Entity, - const InitializationKind &Kind, - InitListExpr *InitList, - InitializationSequence &Sequence); - /// \brief Attempt list initialization of a reference. static void TryReferenceListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitListExpr *InitList, - InitializationSequence &Sequence) -{ + InitializationSequence &Sequence) { // First, catch C++03 where this isn't possible. if (!S.getLangOpts().CPlusPlus11) { Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); @@ -3187,11 +3367,36 @@ static void TryListInitialization(Sema &S, return; } } + if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() && + InitList->getNumInits() == 1 && + InitList->getInit(0)->getType()->isRecordType()) { + // - Otherwise, if the initializer list has a single element of type E + // [...references are handled above...], the object or reference is + // initialized from that element; if a narrowing conversion is required + // to convert the element to T, the program is ill-formed. + // + // Per core-24034, this is direct-initialization if we were performing + // direct-list-initialization and copy-initialization otherwise. + // We can't use InitListChecker for this, because it always performs + // copy-initialization. This only matters if we might use an 'explicit' + // conversion operator, so we only need to handle the cases where the source + // is of record type. + InitializationKind SubKind = + Kind.getKind() == InitializationKind::IK_DirectList + ? InitializationKind::CreateDirect(Kind.getLocation(), + InitList->getLBraceLoc(), + InitList->getRBraceLoc()) + : Kind; + Expr *SubInit[1] = { InitList->getInit(0) }; + Sequence.InitializeFrom(S, Entity, SubKind, SubInit, + /*TopLevelOfInitList*/true); + if (Sequence) + Sequence.RewrapReferenceInitList(Entity.getType(), InitList); + return; + } InitListChecker CheckInitList(S, Entity, InitList, - DestType, /*VerifyOnly=*/true, - Kind.getKind() != InitializationKind::IK_DirectList || - !S.getLangOpts().CPlusPlus11); + DestType, /*VerifyOnly=*/true); if (CheckInitList.HadError()) { Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed); return; @@ -3235,8 +3440,8 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. bool AllowExplicit = Kind.AllowExplicit(); - bool AllowExplicitConvs = Kind.allowExplicitConversionFunctions(); - + bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding(); + const RecordType *T1RecordType = 0; if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) && !S.RequireCompleteType(Kind.getLocation(), T1, 0)) { @@ -3249,7 +3454,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // be changed while iterating (e.g. because of deserialization). // To be safe we copy the lookup results to a new container. SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end()); - for (SmallVector<NamedDecl*, 16>::iterator + for (SmallVectorImpl<NamedDecl *>::iterator CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) { NamedDecl *D = *CI; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); @@ -3503,7 +3708,7 @@ static void TryReferenceInitializationCore(Sema &S, // // - If the reference is an lvalue reference and the initializer // expression - // Note the analogous bullet points for rvlaue refs to functions. Because + // Note the analogous bullet points for rvalue refs to functions. Because // there are no function rvalues in C++, rvalue refs to functions are treated // like lvalue refs. OverloadingResult ConvOvlResult = OR_Success; @@ -3544,20 +3749,17 @@ static void TryReferenceInitializationCore(Sema &S, // applicable conversion functions (13.3.1.6) and choosing the best // one through overload resolution (13.3)), // If we have an rvalue ref to function type here, the rhs must be - // an rvalue. + // an rvalue. DR1287 removed the "implicitly" here. if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() && (isLValueRef || InitCategory.isRValue())) { - ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, - Initializer, - /*AllowRValues=*/isRValueRef, - Sequence); + ConvOvlResult = TryRefInitWithConversionFunction( + S, Entity, Kind, Initializer, /*AllowRValues*/isRValueRef, Sequence); if (ConvOvlResult == OR_Success) return; - if (ConvOvlResult != OR_No_Viable_Function) { + if (ConvOvlResult != OR_No_Viable_Function) Sequence.SetOverloadFailure( - InitializationSequence::FK_ReferenceInitOverloadFailed, - ConvOvlResult); - } + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); } } @@ -3629,16 +3831,16 @@ static void TryReferenceInitializationCore(Sema &S, // reference-related to T2, and can be implicitly converted to an // xvalue, class prvalue, or function lvalue of type "cv3 T3", // where "cv1 T1" is reference-compatible with "cv3 T3", + // + // DR1287 removes the "implicitly" here. if (T2->isRecordType()) { if (RefRelationship == Sema::Ref_Incompatible) { - ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, - Kind, Initializer, - /*AllowRValues=*/true, - Sequence); + ConvOvlResult = TryRefInitWithConversionFunction( + S, Entity, Kind, Initializer, /*AllowRValues*/true, Sequence); if (ConvOvlResult) Sequence.SetOverloadFailure( - InitializationSequence::FK_ReferenceInitOverloadFailed, - ConvOvlResult); + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); return; } @@ -3657,19 +3859,17 @@ static void TryReferenceInitializationCore(Sema &S, // - Otherwise, a temporary of type "cv1 T1" is created and initialized // from the initializer expression using the rules for a non-reference - // copy initialization (8.5). The reference is then bound to the + // copy-initialization (8.5). The reference is then bound to the // temporary. [...] - // Determine whether we are allowed to call explicit constructors or - // explicit conversion operators. - bool AllowExplicit = Kind.AllowExplicit(); - InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1); + // FIXME: Why do we use an implicit conversion here rather than trying + // copy-initialization? ImplicitConversionSequence ICS = S.TryImplicitConversion(Initializer, TempEntity.getType(), - /*SuppressUserConversions*/ false, - AllowExplicit, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, /*FIXME:InOverloadResolution=*/false, /*CStyle=*/Kind.isCStyleOrFunctionalCast(), /*AllowObjCWritebackConversion=*/false); @@ -3848,7 +4048,8 @@ static void TryUserDefinedConversion(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr *Initializer, - InitializationSequence &Sequence) { + InitializationSequence &Sequence, + bool TopLevelOfInitList) { QualType DestType = Entity.getType(); assert(!DestType->isReferenceType() && "References are handled elsewhere"); QualType SourceType = Initializer->getType(); @@ -3877,7 +4078,7 @@ static void TryUserDefinedConversion(Sema &S, // be changed while iterating. To be safe we copy the lookup results // to a new container. SmallVector<NamedDecl*, 8> CopyOfCon(R.begin(), R.end()); - for (SmallVector<NamedDecl*, 8>::iterator + for (SmallVectorImpl<NamedDecl *>::iterator Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end(); Con != ConEnd; ++Con) { NamedDecl *D = *Con; @@ -3999,10 +4200,28 @@ static void TryUserDefinedConversion(Sema &S, ImplicitConversionSequence ICS; ICS.setStandard(); ICS.Standard = Best->FinalConversion; - Sequence.AddConversionSequenceStep(ICS, DestType); + Sequence.AddConversionSequenceStep(ICS, DestType, TopLevelOfInitList); } } +/// An egregious hack for compatibility with libstdc++-4.2: in <tr1/hashtable>, +/// a function with a pointer return type contains a 'return false;' statement. +/// In C++11, 'false' is not a null pointer, so this breaks the build of any +/// code using that header. +/// +/// Work around this by treating 'return false;' as zero-initializing the result +/// if it's used in a pointer-returning function in a system header. +static bool isLibstdcxxPointerReturnFalseHack(Sema &S, + const InitializedEntity &Entity, + const Expr *Init) { + return S.getLangOpts().CPlusPlus11 && + Entity.getKind() == InitializedEntity::EK_Result && + Entity.getType()->isPointerType() && + isa<CXXBoolLiteralExpr>(Init) && + !cast<CXXBoolLiteralExpr>(Init)->getValue() && + S.getSourceManager().isInSystemHeader(Init->getExprLoc()); +} + /// The non-zero enum values here are indexes into diagnostic alternatives. enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar }; @@ -4192,8 +4411,17 @@ static bool TryOCLZeroEventInitialization(Sema &S, InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - MultiExprArg Args) + MultiExprArg Args, + bool TopLevelOfInitList) : FailedCandidateSet(Kind.getLocation()) { + InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList); +} + +void InitializationSequence::InitializeFrom(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + MultiExprArg Args, + bool TopLevelOfInitList) { ASTContext &Context = S.Context; // Eliminate non-overload placeholder types in the arguments. We @@ -4283,9 +4511,23 @@ InitializationSequence::InitializationSequence(Sema &S, return; } - if (Initializer && IsStringInit(Initializer, DestAT, Context)) { - TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); - return; + if (Initializer) { + switch (IsStringInit(Initializer, DestAT, Context)) { + case SIF_None: + TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); + return; + case SIF_NarrowStringIntoWideChar: + SetFailed(FK_NarrowStringIntoWideCharArray); + return; + case SIF_WideStringIntoChar: + SetFailed(FK_WideStringIntoCharArray); + return; + case SIF_IncompatWideStringIntoWideChar: + SetFailed(FK_IncompatWideStringIntoWideChar); + return; + case SIF_Other: + break; + } } // Note: as an GNU C extension, we allow initialization of an @@ -4312,8 +4554,10 @@ InitializationSequence::InitializationSequence(Sema &S, TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer), *this); AddParenthesizedArrayInitStep(DestType); - } else if (DestAT->getElementType()->isAnyCharacterType()) + } else if (DestAT->getElementType()->isCharType()) SetFailed(FK_ArrayNeedsInitListOrStringLiteral); + else if (IsWideCharCompatible(DestAT->getElementType(), Context)) + SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral); else SetFailed(FK_ArrayNeedsInitList); @@ -4323,7 +4567,7 @@ InitializationSequence::InitializationSequence(Sema &S, // Determine whether we should consider writeback conversions for // Objective-C ARC. bool allowObjCWritebackConversion = S.getLangOpts().ObjCAutoRefCount && - Entity.getKind() == InitializedEntity::EK_Parameter; + Entity.isParameterKind(); // We're at the end of the line for C: it's either a write-back conversion // or it's a C assignment. There's no need to check anything else. @@ -4367,7 +4611,8 @@ InitializationSequence::InitializationSequence(Sema &S, // 13.3.1.4, and the best one is chosen through overload resolution // (13.3). else - TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this, + TopLevelOfInitList); return; } @@ -4380,7 +4625,8 @@ InitializationSequence::InitializationSequence(Sema &S, // - Otherwise, if the source type is a (possibly cv-qualified) class // type, conversion functions are considered. if (!SourceType.isNull() && SourceType->isRecordType()) { - TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this, + TopLevelOfInitList); MaybeProduceObjCObject(S, *this, Entity); return; } @@ -4423,14 +4669,16 @@ InitializationSequence::InitializationSequence(Sema &S, AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy); } else if (ICS.isBad()) { DeclAccessPair dap; - if (Initializer->getType() == Context.OverloadTy && - !S.ResolveAddressOfOverloadedFunction(Initializer - , DestType, false, dap)) + if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) { + AddZeroInitializationStep(Entity.getType()); + } else if (Initializer->getType() == Context.OverloadTy && + !S.ResolveAddressOfOverloadedFunction(Initializer, DestType, + false, dap)) SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else SetFailed(InitializationSequence::FK_ConversionFailed); } else { - AddConversionSequenceStep(ICS, Entity.getType()); + AddConversionSequenceStep(ICS, Entity.getType(), TopLevelOfInitList); MaybeProduceObjCObject(S, *this, Entity); } @@ -4447,7 +4695,7 @@ InitializationSequence::~InitializationSequence() { // Perform initialization //===----------------------------------------------------------------------===// static Sema::AssignmentAction -getAssignmentAction(const InitializedEntity &Entity) { +getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) { switch(Entity.getKind()) { case InitializedEntity::EK_Variable: case InitializedEntity::EK_New: @@ -4463,10 +4711,18 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Passing; + case InitializedEntity::EK_Parameter_CF_Audited: + if (Entity.getDecl() && + isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext())) + return Sema::AA_Sending; + + return !Diagnose ? Sema::AA_Passing : Sema::AA_Passing_CFAudited; + case InitializedEntity::EK_Result: return Sema::AA_Returning; case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_RelatedResult: // FIXME: Can we tell apart casting vs. converting? return Sema::AA_Casting; @@ -4503,7 +4759,9 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { return false; case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_RelatedResult: return true; } @@ -4527,10 +4785,12 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Member: case InitializedEntity::EK_Variable: case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: return true; } @@ -4548,7 +4808,7 @@ static void LookupCopyAndMoveConstructors(Sema &S, // be changed while iterating (e.g. because of deserialization). // To be safe we copy the lookup results to a new container. SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end()); - for (SmallVector<NamedDecl*, 16>::iterator + for (SmallVectorImpl<NamedDecl *>::iterator CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) { NamedDecl *D = *CI; CXXConstructorDecl *Constructor = 0; @@ -4605,6 +4865,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Member: case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: @@ -4613,6 +4874,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: return Initializer->getLocStart(); } llvm_unreachable("missed an InitializedEntity kind?"); @@ -4823,7 +5085,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, void InitializationSequence::PrintInitLocationNote(Sema &S, const InitializedEntity &Entity) { - if (Entity.getKind() == InitializedEntity::EK_Parameter && Entity.getDecl()) { + if (Entity.isParameterKind() && Entity.getDecl()) { if (Entity.getDecl()->getLocation().isInvalid()) return; @@ -4833,6 +5095,11 @@ void InitializationSequence::PrintInitLocationNote(Sema &S, else S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here); } + else if (Entity.getKind() == InitializedEntity::EK_RelatedResult && + Entity.getMethodDecl()) + S.Diag(Entity.getMethodDecl()->getLocation(), + diag::note_method_return_type_change) + << Entity.getMethodDecl()->getDeclName(); } static bool isReferenceBinding(const InitializationSequence::Step &s) { @@ -4848,6 +5115,7 @@ static bool isExplicitTemporary(const InitializedEntity &Entity, switch (Entity.getKind()) { case InitializedEntity::EK_Temporary: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: break; default: return false; @@ -4872,7 +5140,9 @@ PerformConstructorInitialization(Sema &S, MultiExprArg Args, const InitializationSequence::Step& Step, bool &ConstructorInitRequiresZeroInit, - bool IsListInitialization) { + bool IsListInitialization, + SourceLocation LBraceLoc, + SourceLocation RBraceLoc) { unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step.Function.Function); @@ -4924,15 +5194,17 @@ PerformConstructorInitialization(Sema &S, TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); if (!TSInfo) TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc); - SourceRange ParenRange; - if (Kind.getKind() != InitializationKind::IK_DirectList) - ParenRange = Kind.getParenRange(); + SourceRange ParenOrBraceRange = + (Kind.getKind() == InitializationKind::IK_DirectList) + ? SourceRange(LBraceLoc, RBraceLoc) + : Kind.getParenRange(); CurInit = S.Owned( new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor, TSInfo, ConstructorArgs, - ParenRange, IsListInitialization, + ParenOrBraceRange, HadMultipleCandidates, + IsListInitialization, ConstructorInitRequiresZeroInit)); } else { CXXConstructExpr::ConstructionKind ConstructKind = @@ -4982,7 +5254,7 @@ PerformConstructorInitialization(Sema &S, return ExprError(); if (shouldBindAsTemporary(Entity)) - CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + CurInit = S.MaybeBindToTemporary(CurInit.take()); return CurInit; } @@ -5015,9 +5287,11 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) { return false; case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_LambdaCapture: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: // The entity being initialized might not outlive the full-expression. return false; } @@ -5025,6 +5299,220 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) { llvm_unreachable("unknown entity kind"); } +/// Determine the declaration which an initialized entity ultimately refers to, +/// for the purpose of lifetime-extending a temporary bound to a reference in +/// the initialization of \p Entity. +static const ValueDecl * +getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity, + const ValueDecl *FallbackDecl = 0) { + // C++11 [class.temporary]p5: + switch (Entity.getKind()) { + case InitializedEntity::EK_Variable: + // The temporary [...] persists for the lifetime of the reference + return Entity.getDecl(); + + case InitializedEntity::EK_Member: + // For subobjects, we look at the complete object. + if (Entity.getParent()) + return getDeclForTemporaryLifetimeExtension(*Entity.getParent(), + Entity.getDecl()); + + // except: + // -- A temporary bound to a reference member in a constructor's + // ctor-initializer persists until the constructor exits. + return Entity.getDecl(); + + case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Parameter_CF_Audited: + // -- A temporary bound to a reference parameter in a function call + // persists until the completion of the full-expression containing + // the call. + case InitializedEntity::EK_Result: + // -- The lifetime of a temporary bound to the returned value in a + // function return statement is not extended; the temporary is + // destroyed at the end of the full-expression in the return statement. + case InitializedEntity::EK_New: + // -- A temporary bound to a reference in a new-initializer persists + // until the completion of the full-expression containing the + // new-initializer. + return 0; + + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: + // We don't yet know the storage duration of the surrounding temporary. + // Assume it's got full-expression duration for now, it will patch up our + // storage duration if that's not correct. + return 0; + + case InitializedEntity::EK_ArrayElement: + // For subobjects, we look at the complete object. + return getDeclForTemporaryLifetimeExtension(*Entity.getParent(), + FallbackDecl); + + case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegating: + // We can reach this case for aggregate initialization in a constructor: + // struct A { int &&r; }; + // struct B : A { B() : A{0} {} }; + // In this case, use the innermost field decl as the context. + return FallbackDecl; + + case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaCapture: + case InitializedEntity::EK_Exception: + case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: + return 0; + } + llvm_unreachable("unknown entity kind"); +} + +static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD); + +/// Update a glvalue expression that is used as the initializer of a reference +/// to note that its lifetime is extended. +/// \return \c true if any temporary had its lifetime extended. +static bool performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) { + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + if (ILE->getNumInits() == 1 && ILE->isGLValue()) { + // This is just redundant braces around an initializer. Step over it. + Init = ILE->getInit(0); + } + } + + // Walk past any constructs which we can lifetime-extend across. + Expr *Old; + do { + Old = Init; + + // Step over any subobject adjustments; we may have a materialized + // temporary inside them. + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + Init = const_cast<Expr *>( + Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments)); + + // Per current approach for DR1376, look through casts to reference type + // when performing lifetime extension. + if (CastExpr *CE = dyn_cast<CastExpr>(Init)) + if (CE->getSubExpr()->isGLValue()) + Init = CE->getSubExpr(); + + // FIXME: Per DR1213, subscripting on an array temporary produces an xvalue. + // It's unclear if binding a reference to that xvalue extends the array + // temporary. + } while (Init != Old); + + if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) { + // Update the storage duration of the materialized temporary. + // FIXME: Rebuild the expression instead of mutating it. + ME->setExtendingDecl(ExtendingD); + performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingD); + return true; + } + + return false; +} + +/// Update a prvalue expression that is going to be materialized as a +/// lifetime-extended temporary. +static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) { + // Dig out the expression which constructs the extended temporary. + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + Init = const_cast<Expr *>( + Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments)); + + if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init)) + Init = BTE->getSubExpr(); + + if (CXXStdInitializerListExpr *ILE = + dyn_cast<CXXStdInitializerListExpr>(Init)) { + performReferenceExtension(ILE->getSubExpr(), ExtendingD); + return; + } + + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + if (ILE->getType()->isArrayType()) { + for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I) + performLifetimeExtension(ILE->getInit(I), ExtendingD); + return; + } + + if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) { + assert(RD->isAggregate() && "aggregate init on non-aggregate"); + + // If we lifetime-extend a braced initializer which is initializing an + // aggregate, and that aggregate contains reference members which are + // bound to temporaries, those temporaries are also lifetime-extended. + if (RD->isUnion() && ILE->getInitializedFieldInUnion() && + ILE->getInitializedFieldInUnion()->getType()->isReferenceType()) + performReferenceExtension(ILE->getInit(0), ExtendingD); + else { + unsigned Index = 0; + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); + I != E; ++I) { + if (Index >= ILE->getNumInits()) + break; + if (I->isUnnamedBitfield()) + continue; + Expr *SubInit = ILE->getInit(Index); + if (I->getType()->isReferenceType()) + performReferenceExtension(SubInit, ExtendingD); + else if (isa<InitListExpr>(SubInit) || + isa<CXXStdInitializerListExpr>(SubInit)) + // This may be either aggregate-initialization of a member or + // initialization of a std::initializer_list object. Either way, + // we should recursively lifetime-extend that initializer. + performLifetimeExtension(SubInit, ExtendingD); + ++Index; + } + } + } + } +} + +static void warnOnLifetimeExtension(Sema &S, const InitializedEntity &Entity, + const Expr *Init, bool IsInitializerList, + const ValueDecl *ExtendingDecl) { + // Warn if a field lifetime-extends a temporary. + if (isa<FieldDecl>(ExtendingDecl)) { + if (IsInitializerList) { + S.Diag(Init->getExprLoc(), diag::warn_dangling_std_initializer_list) + << /*at end of constructor*/true; + return; + } + + bool IsSubobjectMember = false; + for (const InitializedEntity *Ent = Entity.getParent(); Ent; + Ent = Ent->getParent()) { + if (Ent->getKind() != InitializedEntity::EK_Base) { + IsSubobjectMember = true; + break; + } + } + S.Diag(Init->getExprLoc(), + diag::warn_bind_ref_member_to_temporary) + << ExtendingDecl << Init->getSourceRange() + << IsSubobjectMember << IsInitializerList; + if (IsSubobjectMember) + S.Diag(ExtendingDecl->getLocation(), + diag::note_ref_subobject_of_member_declared_here); + else + S.Diag(ExtendingDecl->getLocation(), + diag::note_ref_or_ptr_member_declared_here) + << /*is pointer*/false; + } +} + +static void DiagnoseNarrowingInInitList(Sema &S, + const ImplicitConversionSequence &ICS, + QualType PreNarrowingType, + QualType EntityType, + const Expr *PostInit); + ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, @@ -5094,7 +5582,7 @@ InitializationSequence::Perform(Sema &S, if (S.getLangOpts().CPlusPlus11 && Entity.getType()->isReferenceType() && Args.size() == 1 && isa<InitListExpr>(Args[0]) && - Entity.getKind() != InitializedEntity::EK_Parameter) { + !Entity.isParameterKind()) { // Produce a C++98 compatibility warning if we are initializing a reference // from an initializer list. For parameters, we produce a better warning // elsewhere. @@ -5142,6 +5630,7 @@ InitializationSequence::Perform(Sema &S, case SK_QualificationConversionRValue: case SK_LValueToRValue: case SK_ConversionSequence: + case SK_ConversionSequenceNoNarrowing: case SK_ListInitialization: case SK_UnwrapInitList: case SK_RewrapInitList: @@ -5260,9 +5749,19 @@ InitializationSequence::Perform(Sema &S, if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); + // Even though we didn't materialize a temporary, the binding may still + // extend the lifetime of a temporary. This happens if we bind a reference + // to the result of a cast to reference type. + if (const ValueDecl *ExtendingDecl = + getDeclForTemporaryLifetimeExtension(Entity)) { + if (performReferenceExtension(CurInit.get(), ExtendingDecl)) + warnOnLifetimeExtension(S, Entity, CurInit.get(), false, + ExtendingDecl); + } + break; - case SK_BindReferenceToTemporary: + case SK_BindReferenceToTemporary: { // Make sure the "temporary" is actually an rvalue. assert(CurInit.get()->isRValue() && "not a temporary"); @@ -5270,19 +5769,33 @@ InitializationSequence::Perform(Sema &S, if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); + // Maybe lifetime-extend the temporary's subobjects to match the + // entity's lifetime. + const ValueDecl *ExtendingDecl = + getDeclForTemporaryLifetimeExtension(Entity); + if (ExtendingDecl) { + performLifetimeExtension(CurInit.get(), ExtendingDecl); + warnOnLifetimeExtension(S, Entity, CurInit.get(), false, ExtendingDecl); + } + // Materialize the temporary into memory. - CurInit = new (S.Context) MaterializeTemporaryExpr( - Entity.getType().getNonReferenceType(), - CurInit.get(), - Entity.getType()->isLValueReferenceType()); + MaterializeTemporaryExpr *MTE = new (S.Context) MaterializeTemporaryExpr( + Entity.getType().getNonReferenceType(), CurInit.get(), + Entity.getType()->isLValueReferenceType(), ExtendingDecl); // If we're binding to an Objective-C object that has lifetime, we - // need cleanups. - if (S.getLangOpts().ObjCAutoRefCount && - CurInit.get()->getType()->isObjCLifetimeType()) + // need cleanups. Likewise if we're extending this temporary to automatic + // storage duration -- we need to register its cleanup during the + // full-expression's cleanups. + if ((S.getLangOpts().ObjCAutoRefCount && + MTE->getType()->isObjCLifetimeType()) || + (MTE->getStorageDuration() == SD_Automatic && + MTE->getType().isDestructedType())) S.ExprNeedsCleanups = true; - + + CurInit = S.Owned(MTE); break; + } case SK_ExtraneousCopyToTemporary: CurInit = CopyObject(S, Step->Type, Entity, CurInit, @@ -5416,8 +5929,9 @@ InitializationSequence::Perform(Sema &S, break; } - case SK_ConversionSequence: { - Sema::CheckedConversionKind CCK + case SK_ConversionSequence: + case SK_ConversionSequenceNoNarrowing: { + Sema::CheckedConversionKind CCK = Kind.isCStyleCast()? Sema::CCK_CStyleCast : Kind.isFunctionalCast()? Sema::CCK_FunctionalCast : Kind.isExplicitCast()? Sema::CCK_OtherCast @@ -5428,31 +5942,32 @@ InitializationSequence::Perform(Sema &S, if (CurInitExprRes.isInvalid()) return ExprError(); CurInit = CurInitExprRes; + + if (Step->Kind == SK_ConversionSequenceNoNarrowing && + S.getLangOpts().CPlusPlus && !CurInit.get()->isValueDependent()) + DiagnoseNarrowingInInitList(S, *Step->ICS, SourceType, Entity.getType(), + CurInit.get()); break; } case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); - // Hack: We must pass *ResultType if available in order to set the type - // of arrays, e.g. in 'int ar[] = {1, 2, 3};'. - // But in 'const X &x = {1, 2, 3};' we're supposed to initialize a - // temporary, not a reference, so we should pass Ty. - // Worst case: 'const int (&arref)[] = {1, 2, 3};'. - // Since this step is never used for a reference directly, we explicitly - // unwrap references here and rewrap them afterwards. - // We also need to create a InitializeTemporary entity for this. - QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type; - bool IsTemporary = Entity.getType()->isReferenceType(); + // If we're not initializing the top-level entity, we need to create an + // InitializeTemporary entity for our target type. + QualType Ty = Step->Type; + bool IsTemporary = !S.Context.hasSameType(Entity.getType(), Ty); InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty); InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity; InitListChecker PerformInitList(S, InitEntity, - InitList, Ty, /*VerifyOnly=*/false, - Kind.getKind() != InitializationKind::IK_DirectList || - !S.getLangOpts().CPlusPlus11); + InitList, Ty, /*VerifyOnly=*/false); if (PerformInitList.HadError()) return ExprError(); - if (ResultType) { + // Hack: We must update *ResultType if available in order to set the + // bounds of arrays, e.g. in 'int ar[] = {1, 2, 3};'. + // Worst case: 'const int (&arref)[] = {1, 2, 3};'. + if (ResultType && + ResultType->getNonReferenceType()->isIncompleteArrayType()) { if ((*ResultType)->isRValueReferenceType()) Ty = S.Context.getRValueReferenceType(Ty); else if ((*ResultType)->isLValueReferenceType()) @@ -5489,7 +6004,9 @@ InitializationSequence::Perform(Sema &S, Entity, Kind, Arg, *Step, ConstructorInitRequiresZeroInit, - /*IsListInitialization*/ true); + /*IsListInitialization*/ true, + InitList->getLBraceLoc(), + InitList->getRBraceLoc()); break; } @@ -5523,7 +6040,9 @@ InitializationSequence::Perform(Sema &S, : Entity, Kind, Args, *Step, ConstructorInitRequiresZeroInit, - /*IsListInitialization*/ false); + /*IsListInitialization*/ false, + /*LBraceLoc*/ SourceLocation(), + /*RBraceLoc*/ SourceLocation()); break; } @@ -5558,7 +6077,8 @@ InitializationSequence::Perform(Sema &S, QualType SourceType = CurInit.get()->getType(); ExprResult Result = CurInit; Sema::AssignConvertType ConvTy = - S.CheckSingleAssignmentConstraints(Step->Type, Result); + S.CheckSingleAssignmentConstraints(Step->Type, Result, true, + Entity.getKind() == InitializedEntity::EK_Parameter_CF_Audited); if (Result.isInvalid()) return ExprError(); CurInit = Result; @@ -5566,7 +6086,7 @@ InitializationSequence::Perform(Sema &S, // If this is a call, allow conversion to a transparent union. ExprResult CurInitExprRes = CurInit; if (ConvTy != Sema::Compatible && - Entity.getKind() == InitializedEntity::EK_Parameter && + Entity.isParameterKind() && S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExprRes) == Sema::Compatible) ConvTy = Sema::Compatible; @@ -5578,7 +6098,7 @@ InitializationSequence::Perform(Sema &S, if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), Step->Type, SourceType, CurInit.get(), - getAssignmentAction(Entity), + getAssignmentAction(Entity, true), &Complained)) { PrintInitLocationNote(S, Entity); return ExprError(); @@ -5645,67 +6165,46 @@ InitializationSequence::Perform(Sema &S, break; case SK_StdInitializerList: { - QualType Dest = Step->Type; - QualType E; - bool Success = S.isStdInitializerList(Dest.getNonReferenceType(), &E); - (void)Success; - assert(Success && "Destination type changed?"); - - // If the element type has a destructor, check it. - if (CXXRecordDecl *RD = E->getAsCXXRecordDecl()) { - if (!RD->hasIrrelevantDestructor()) { - if (CXXDestructorDecl *Destructor = S.LookupDestructor(RD)) { - S.MarkFunctionReferenced(Kind.getLocation(), Destructor); - S.CheckDestructorAccess(Kind.getLocation(), Destructor, - S.PDiag(diag::err_access_dtor_temp) << E); - if (S.DiagnoseUseOfDecl(Destructor, Kind.getLocation())) - return ExprError(); - } - } - } + S.Diag(CurInit.get()->getExprLoc(), + diag::warn_cxx98_compat_initializer_list_init) + << CurInit.get()->getSourceRange(); - InitListExpr *ILE = cast<InitListExpr>(CurInit.take()); - S.Diag(ILE->getExprLoc(), diag::warn_cxx98_compat_initializer_list_init) - << ILE->getSourceRange(); - unsigned NumInits = ILE->getNumInits(); - SmallVector<Expr*, 16> Converted(NumInits); - InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary( - S.Context.getConstantArrayType(E, - llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), - NumInits), - ArrayType::Normal, 0)); - InitializedEntity Element =InitializedEntity::InitializeElement(S.Context, - 0, HiddenArray); - for (unsigned i = 0; i < NumInits; ++i) { - Element.setElementIndex(i); - ExprResult Init = S.Owned(ILE->getInit(i)); - ExprResult Res = S.PerformCopyInitialization( - Element, Init.get()->getExprLoc(), Init, - /*TopLevelOfInitList=*/ true); - assert(!Res.isInvalid() && "Result changed since try phase."); - Converted[i] = Res.take(); + // Maybe lifetime-extend the array temporary's subobjects to match the + // entity's lifetime. + const ValueDecl *ExtendingDecl = + getDeclForTemporaryLifetimeExtension(Entity); + if (ExtendingDecl) { + performLifetimeExtension(CurInit.get(), ExtendingDecl); + warnOnLifetimeExtension(S, Entity, CurInit.get(), true, ExtendingDecl); } - InitListExpr *Semantic = new (S.Context) - InitListExpr(S.Context, ILE->getLBraceLoc(), - Converted, ILE->getRBraceLoc()); - Semantic->setSyntacticForm(ILE); - Semantic->setType(Dest); - Semantic->setInitializesStdInitializerList(); - CurInit = S.Owned(Semantic); + + // Materialize the temporary into memory. + MaterializeTemporaryExpr *MTE = new (S.Context) + MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(), + /*lvalue reference*/ false, ExtendingDecl); + + // Wrap it in a construction of a std::initializer_list<T>. + CurInit = S.Owned( + new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE)); + + // Bind the result, in case the library has given initializer_list a + // non-trivial destructor. + if (shouldBindAsTemporary(Entity)) + CurInit = S.MaybeBindToTemporary(CurInit.take()); break; } + case SK_OCLSamplerInit: { assert(Step->Type->isSamplerT() && "Sampler initialization on non sampler type."); QualType SourceType = CurInit.get()->getType(); - InitializedEntity::EntityKind EntityKind = Entity.getKind(); - if (EntityKind == InitializedEntity::EK_Parameter) { + if (Entity.isParameterKind()) { if (!SourceType->isSamplerT()) S.Diag(Kind.getLocation(), diag::err_sampler_argument_required) << SourceType; - } else if (EntityKind != InitializedEntity::EK_Variable) { + } else if (Entity.getKind() != InitializedEntity::EK_Variable) { llvm_unreachable("Invalid EntityKind!"); } @@ -5794,6 +6293,28 @@ static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity, } } +static void diagnoseListInit(Sema &S, const InitializedEntity &Entity, + InitListExpr *InitList) { + QualType DestType = Entity.getType(); + + QualType E; + if (S.getLangOpts().CPlusPlus11 && S.isStdInitializerList(DestType, &E)) { + QualType ArrayType = S.Context.getConstantArrayType( + E.withConst(), + llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), + InitList->getNumInits()), + clang::ArrayType::Normal, 0); + InitializedEntity HiddenArray = + InitializedEntity::InitializeTemporary(ArrayType); + return diagnoseListInit(S, HiddenArray, InitList); + } + + InitListChecker DiagnoseInitList(S, Entity, InitList, DestType, + /*VerifyOnly=*/false); + assert(DiagnoseInitList.HadError() && + "Inconsistent init list check result."); +} + bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -5821,14 +6342,27 @@ bool InitializationSequence::Diagnose(Sema &S, break; case FK_ArrayNeedsInitList: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 0; + break; case FK_ArrayNeedsInitListOrStringLiteral: - S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) - << (Failure == FK_ArrayNeedsInitListOrStringLiteral); + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 1; + break; + case FK_ArrayNeedsInitListOrWideStringLiteral: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 2; + break; + case FK_NarrowStringIntoWideCharArray: + S.Diag(Kind.getLocation(), diag::err_array_init_narrow_string_into_wchar); + break; + case FK_WideStringIntoCharArray: + S.Diag(Kind.getLocation(), diag::err_array_init_wide_string_into_char); + break; + case FK_IncompatWideStringIntoWideChar: + S.Diag(Kind.getLocation(), + diag::err_array_init_incompat_wide_string_into_wchar); break; - case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: - S.Diag(Kind.getLocation(), + S.Diag(Kind.getLocation(), (Failure == FK_ArrayTypeMismatch ? diag::err_array_init_different_type : diag::err_array_init_non_constant_array)) @@ -5868,9 +6402,14 @@ bool InitializationSequence::Diagnose(Sema &S, break; case OR_No_Viable_Function: - S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) - << Args[0]->getType() << DestType.getNonReferenceType() - << Args[0]->getSourceRange(); + if (!S.RequireCompleteType(Kind.getLocation(), + DestType.getNonReferenceType(), + diag::err_typecheck_nonviable_condition_incomplete, + Args[0]->getType(), Args[0]->getSourceRange())) + S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) + << Args[0]->getType() << Args[0]->getSourceRange() + << DestType.getNonReferenceType(); + FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args); break; @@ -6115,14 +6654,8 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_ListInitializationFailed: { // Run the init list checker again to emit diagnostics. - InitListExpr* InitList = cast<InitListExpr>(Args[0]); - QualType DestType = Entity.getType(); - InitListChecker DiagnoseInitList(S, Entity, InitList, - DestType, /*VerifyOnly=*/false, - Kind.getKind() != InitializationKind::IK_DirectList || - !S.getLangOpts().CPlusPlus11); - assert(DiagnoseInitList.HadError() && - "Inconsistent init list check result."); + InitListExpr *InitList = cast<InitListExpr>(Args[0]); + diagnoseListInit(S, Entity, InitList); break; } @@ -6131,37 +6664,6 @@ bool InitializationSequence::Diagnose(Sema &S, break; } - case FK_InitListElementCopyFailure: { - // Try to perform all copies again. - InitListExpr* InitList = cast<InitListExpr>(Args[0]); - unsigned NumInits = InitList->getNumInits(); - QualType DestType = Entity.getType(); - QualType E; - bool Success = S.isStdInitializerList(DestType.getNonReferenceType(), &E); - (void)Success; - assert(Success && "Where did the std::initializer_list go?"); - InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary( - S.Context.getConstantArrayType(E, - llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), - NumInits), - ArrayType::Normal, 0)); - InitializedEntity Element = InitializedEntity::InitializeElement(S.Context, - 0, HiddenArray); - // Show at most 3 errors. Otherwise, you'd get a lot of errors for errors - // where the init list type is wrong, e.g. - // std::initializer_list<void*> list = { 1, 2, 3, 4, 5, 6, 7, 8 }; - // FIXME: Emit a note if we hit the limit? - int ErrorCount = 0; - for (unsigned i = 0; i < NumInits && ErrorCount < 3; ++i) { - Element.setElementIndex(i); - ExprResult Init = S.Owned(InitList->getInit(i)); - if (S.PerformCopyInitialization(Element, Init.get()->getExprLoc(), Init) - .isInvalid()) - ++ErrorCount; - } - break; - } - case FK_ExplicitConstructor: { S.Diag(Kind.getLocation(), diag::err_selected_explicit_constructor) << Args[0]->getSourceRange(); @@ -6197,6 +6699,22 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "array requires initializer list or string literal"; break; + case FK_ArrayNeedsInitListOrWideStringLiteral: + OS << "array requires initializer list or wide string literal"; + break; + + case FK_NarrowStringIntoWideCharArray: + OS << "narrow string into wide char array"; + break; + + case FK_WideStringIntoCharArray: + OS << "wide string into char array"; + break; + + case FK_IncompatWideStringIntoWideChar: + OS << "incompatible wide string into wide char array"; + break; + case FK_ArrayTypeMismatch: OS << "array type mismatch"; break; @@ -6285,10 +6803,6 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "list constructor overloading failed"; break; - case FK_InitListElementCopyFailure: - OS << "copy construction of initializer list element failed"; - break; - case FK_ExplicitConstructor: OS << "list copy initialization chose explicit constructor"; break; @@ -6362,7 +6876,13 @@ void InitializationSequence::dump(raw_ostream &OS) const { case SK_ConversionSequence: OS << "implicit conversion sequence ("; - S->ICS->DebugPrint(); // FIXME: use OS + S->ICS->dump(); // FIXME: use OS + OS << ")"; + break; + + case SK_ConversionSequenceNoNarrowing: + OS << "implicit conversion sequence with narrowing prohibited ("; + S->ICS->dump(); // FIXME: use OS OS << ")"; break; @@ -6445,20 +6965,11 @@ void InitializationSequence::dump() const { dump(llvm::errs()); } -static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq, +static void DiagnoseNarrowingInInitList(Sema &S, + const ImplicitConversionSequence &ICS, + QualType PreNarrowingType, QualType EntityType, - const Expr *PreInit, const Expr *PostInit) { - if (Seq.step_begin() == Seq.step_end() || PreInit->isValueDependent()) - return; - - // A narrowing conversion can only appear as the final implicit conversion in - // an initialization sequence. - const InitializationSequence::Step &LastStep = Seq.step_end()[-1]; - if (LastStep.Kind != InitializationSequence::SK_ConversionSequence) - return; - - const ImplicitConversionSequence &ICS = *LastStep.ICS; const StandardConversionSequence *SCS = 0; switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: @@ -6473,13 +6984,6 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq, return; } - // Determine the type prior to the narrowing conversion. If a conversion - // operator was used, this may be different from both the type of the entity - // and of the pre-initialization expression. - QualType PreNarrowingType = PreInit->getType(); - if (Seq.step_begin() + 1 != Seq.step_end()) - PreNarrowingType = Seq.step_end()[-2].Type; - // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion. APValue ConstantValue; QualType ConstantType; @@ -6494,11 +6998,9 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq, // narrowing conversion even if the value is a constant and can be // represented exactly as an integer. S.Diag(PostInit->getLocStart(), - S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11? - diag::warn_init_list_type_narrowing - : S.isSFINAEContext()? - diag::err_init_list_type_narrowing_sfinae - : diag::err_init_list_type_narrowing) + (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11) + ? diag::warn_init_list_type_narrowing + : diag::ext_init_list_type_narrowing) << PostInit->getSourceRange() << PreNarrowingType.getLocalUnqualifiedType() << EntityType.getLocalUnqualifiedType(); @@ -6507,11 +7009,9 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq, case NK_Constant_Narrowing: // A constant value was narrowed. S.Diag(PostInit->getLocStart(), - S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11? - diag::warn_init_list_constant_narrowing - : S.isSFINAEContext()? - diag::err_init_list_constant_narrowing_sfinae - : diag::err_init_list_constant_narrowing) + (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11) + ? diag::warn_init_list_constant_narrowing + : diag::ext_init_list_constant_narrowing) << PostInit->getSourceRange() << ConstantValue.getAsString(S.getASTContext(), ConstantType) << EntityType.getLocalUnqualifiedType(); @@ -6520,11 +7020,9 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq, case NK_Variable_Narrowing: // A variable's value may have been narrowed. S.Diag(PostInit->getLocStart(), - S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11? - diag::warn_init_list_variable_narrowing - : S.isSFINAEContext()? - diag::err_init_list_variable_narrowing_sfinae - : diag::err_init_list_variable_narrowing) + (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11) + ? diag::warn_init_list_variable_narrowing + : diag::ext_init_list_variable_narrowing) << PostInit->getSourceRange() << PreNarrowingType.getLocalUnqualifiedType() << EntityType.getLocalUnqualifiedType(); @@ -6592,14 +7090,10 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(), EqualLoc, AllowExplicit); - InitializationSequence Seq(*this, Entity, Kind, InitE); + InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList); Init.release(); ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE); - if (!Result.isInvalid() && TopLevelOfInitList) - DiagnoseNarrowingInInitList(*this, Seq, Entity.getType(), - InitE, Result.get()); - return Result; } |