summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaInit.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
commit486754660bb926339aefcf012a3f848592babb8b (patch)
treeecdbc446c9876f4f120f701c243373cd3cb43db3 /lib/Sema/SemaInit.cpp
parent55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff)
Notes
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r--lib/Sema/SemaInit.cpp1076
1 files changed, 799 insertions, 277 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 011051da58e50..3ee5ec4a4929e 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -15,6 +15,7 @@
#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/TargetInfo.h"
#include "clang/Sema/Designator.h"
@@ -32,7 +33,7 @@ using namespace clang;
// Sema Initialization Checking
//===----------------------------------------------------------------------===//
-/// \brief Check whether T is compatible with a wide character type (wchar_t,
+/// 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))
@@ -49,10 +50,12 @@ enum StringInitFailureKind {
SIF_NarrowStringIntoWideChar,
SIF_WideStringIntoChar,
SIF_IncompatWideStringIntoWideChar,
+ SIF_UTF8StringIntoPlainChar,
+ SIF_PlainStringIntoUTF8Char,
SIF_Other
};
-/// \brief Check whether the array of type AT can be initialized by the Init
+/// 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.
@@ -77,12 +80,21 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
Context.getCanonicalType(AT->getElementType()).getUnqualifiedType();
switch (SL->getKind()) {
- case StringLiteral::Ascii:
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 SIF_None;
+ 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;
@@ -94,7 +106,7 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
case StringLiteral::UTF16:
if (Context.typesAreCompatible(Context.Char16Ty, ElemTy))
return SIF_None;
- if (ElemTy->isCharType())
+ if (ElemTy->isCharType() || ElemTy->isChar8Type())
return SIF_WideStringIntoChar;
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
@@ -102,7 +114,7 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
case StringLiteral::UTF32:
if (Context.typesAreCompatible(Context.Char32Ty, ElemTy))
return SIF_None;
- if (ElemTy->isCharType())
+ if (ElemTy->isCharType() || ElemTy->isChar8Type())
return SIF_WideStringIntoChar;
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
@@ -110,7 +122,7 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
case StringLiteral::Wide:
if (Context.typesAreCompatible(Context.getWideCharType(), ElemTy))
return SIF_None;
- if (ElemTy->isCharType())
+ if (ElemTy->isCharType() || ElemTy->isChar8Type())
return SIF_WideStringIntoChar;
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
@@ -206,7 +218,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
namespace {
-/// @brief Semantic checking for initializer lists.
+/// 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.,
@@ -352,6 +364,7 @@ class InitListChecker {
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,
@@ -365,7 +378,7 @@ public:
bool TreatUnavailableAsInvalid);
bool HadError() { return hadError; }
- // @brief Retrieves the fully-structured initializer list used for
+ // Retrieves the fully-structured initializer list used for
// semantic analysis and code generation.
InitListExpr *getFullyStructuredList() const { return FullyStructuredList; }
};
@@ -517,12 +530,13 @@ void InitListChecker::FillInEmptyInitForBase(
ILE->setInit(Init, BaseInit.getAs<Expr>());
} else if (InitListExpr *InnerILE =
dyn_cast<InitListExpr>(ILE->getInit(Init))) {
- FillInEmptyInitializations(BaseEntity, InnerILE,
- RequiresSecondPass, FillWithNoInit);
+ FillInEmptyInitializations(BaseEntity, InnerILE, RequiresSecondPass,
+ ILE, Init, FillWithNoInit);
} else if (DesignatedInitUpdateExpr *InnerDIUE =
dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(BaseEntity, InnerDIUE->getUpdater(),
- RequiresSecondPass, /*FillWithNoInit =*/true);
+ RequiresSecondPass, ILE, Init,
+ /*FillWithNoInit =*/true);
}
}
@@ -559,6 +573,7 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
hadError = true;
return;
}
+ SemaRef.checkInitializerLifetime(MemberEntity, DIE.get());
if (Init < NumInits)
ILE->setInit(Init, DIE.get());
else {
@@ -605,24 +620,43 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
} else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init)))
FillInEmptyInitializations(MemberEntity, InnerILE,
- RequiresSecondPass, FillWithNoInit);
+ RequiresSecondPass, ILE, Init, FillWithNoInit);
else if (DesignatedInitUpdateExpr *InnerDIUE
= dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init)))
FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(),
- RequiresSecondPass, /*FillWithNoInit =*/ true);
+ RequiresSecondPass, ILE, Init,
+ /*FillWithNoInit =*/true);
}
/// Recursively replaces NULL values within the given initializer list
/// with expressions that perform value-initialization of the
-/// appropriate type.
+/// appropriate type, and finish off the InitListExpr formation.
void
InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
InitListExpr *ILE,
bool &RequiresSecondPass,
+ InitListExpr *OuterILE,
+ unsigned OuterIndex,
bool FillWithNoInit) {
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
+ // If this is a nested initializer list, we might have changed its contents
+ // (and therefore some of its properties, such as instantiation-dependence)
+ // while filling it in. Inform the outer initializer list so that its state
+ // can be updated to match.
+ // FIXME: We should fully build the inner initializers before constructing
+ // the outer InitListExpr instead of mutating AST nodes after they have
+ // been used as subexpressions of other nodes.
+ struct UpdateOuterILEWithUpdatedInit {
+ InitListExpr *Outer;
+ unsigned OuterIndex;
+ ~UpdateOuterILEWithUpdatedInit() {
+ if (Outer)
+ Outer->setInit(OuterIndex, Outer->getInit(OuterIndex));
+ }
+ } UpdateOuterRAII = {OuterILE, OuterIndex};
+
// A transparent ILE is not performing aggregate initialization and should
// not be filled in.
if (ILE->isTransparent())
@@ -719,6 +753,9 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
+ if (Init >= NumInits && ILE->hasArrayFiller())
+ return;
+
Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
if (!InitExpr && Init < NumInits && ILE->hasArrayFiller())
ILE->setInit(Init, ILE->getArrayFiller());
@@ -769,11 +806,12 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
} else if (InitListExpr *InnerILE
= dyn_cast_or_null<InitListExpr>(InitExpr))
FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass,
- FillWithNoInit);
+ ILE, Init, FillWithNoInit);
else if (DesignatedInitUpdateExpr *InnerDIUE
= dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr))
FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(),
- RequiresSecondPass, /*FillWithNoInit =*/ true);
+ RequiresSecondPass, ILE, Init,
+ /*FillWithNoInit =*/true);
}
}
@@ -795,10 +833,11 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
if (!hadError && !VerifyOnly) {
bool RequiresSecondPass = false;
- FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass);
+ FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass,
+ /*OuterILE=*/nullptr, /*OuterIndex=*/0);
if (RequiresSecondPass && !hadError)
FillInEmptyInitializations(Entity, FullyStructuredList,
- RequiresSecondPass);
+ RequiresSecondPass, nullptr, 0);
}
}
@@ -982,6 +1021,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_Binding:
+ case InitializedEntity::EK_StmtExprResult:
llvm_unreachable("unexpected braced scalar init");
}
@@ -1162,10 +1202,12 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
if (!hadError && !VerifyOnly) {
bool RequiresSecondPass = false;
FillInEmptyInitializations(Entity, InnerStructuredList,
- RequiresSecondPass);
+ RequiresSecondPass, StructuredList,
+ StructuredIndex);
if (RequiresSecondPass && !hadError)
FillInEmptyInitializations(Entity, InnerStructuredList,
- RequiresSecondPass);
+ RequiresSecondPass, StructuredList,
+ StructuredIndex);
}
++StructuredIndex;
++Index;
@@ -1989,7 +2031,7 @@ void InitListChecker::CheckStructUnionTypes(
StructuredList, StructuredIndex);
}
-/// \brief Expand a field designator that refers to a member of an
+/// 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.
///
@@ -2053,7 +2095,7 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
} // end anonymous namespace
-/// @brief Check the well-formedness of a C99 designated initializer.
+/// 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
@@ -2960,6 +3002,7 @@ DeclarationName InitializedEntity::getName() const {
return DeclarationName(Capture.VarID);
case EK_Result:
+ case EK_StmtExprResult:
case EK_Exception:
case EK_New:
case EK_Temporary:
@@ -2990,6 +3033,7 @@ ValueDecl *InitializedEntity::getDecl() const {
return reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
case EK_Result:
+ case EK_StmtExprResult:
case EK_Exception:
case EK_New:
case EK_Temporary:
@@ -3015,6 +3059,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_Exception:
return LocAndNRVO.NRVO;
+ case EK_StmtExprResult:
case EK_Variable:
case EK_Parameter:
case EK_Parameter_CF_Audited:
@@ -3050,6 +3095,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
case EK_Parameter_CF_Audited: OS << "CF audited function Parameter";
break;
case EK_Result: OS << "Result"; break;
+ case EK_StmtExprResult: OS << "StmtExprResult"; break;
case EK_Exception: OS << "Exception"; break;
case EK_Member: OS << "Member"; break;
case EK_Binding: OS << "Binding"; break;
@@ -3160,6 +3206,8 @@ bool InitializationSequence::isAmbiguous() const {
case FK_NarrowStringIntoWideCharArray:
case FK_WideStringIntoCharArray:
case FK_IncompatWideStringIntoWideChar:
+ case FK_PlainStringIntoUTF8Char:
+ case FK_UTF8StringIntoPlainChar:
case FK_AddressOfOverloadFailed: // FIXME: Could do better
case FK_NonConstLValueReferenceBindingToTemporary:
case FK_NonConstLValueReferenceBindingToBitfield:
@@ -3492,7 +3540,8 @@ static void MaybeProduceObjCObject(Sema &S,
/// retainable type, then returns need to immediately retain the
/// object. If an autorelease is required, it will be done at the
/// last instant.
- } else if (Entity.getKind() == InitializedEntity::EK_Result) {
+ } else if (Entity.getKind() == InitializedEntity::EK_Result ||
+ Entity.getKind() == InitializedEntity::EK_StmtExprResult) {
if (!Entity.getType()->isObjCRetainableType())
return;
@@ -3507,7 +3556,7 @@ static void TryListInitialization(Sema &S,
InitializationSequence &Sequence,
bool TreatUnavailableAsInvalid);
-/// \brief When initializing from init list via constructor, handle
+/// When initializing from init list via constructor, handle
/// initialization of an object of type std::initializer_list<T>.
///
/// \return true if we have handled initialization of an object of type
@@ -3533,8 +3582,8 @@ static bool TryInitializerListConstruction(Sema &S,
clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
- InitializationKind Kind =
- InitializationKind::CreateDirectList(List->getExprLoc());
+ InitializationKind Kind = InitializationKind::CreateDirectList(
+ List->getExprLoc(), List->getLocStart(), List->getLocEnd());
TryListInitialization(S, HiddenArray, Kind, List, Sequence,
TreatUnavailableAsInvalid);
if (Sequence)
@@ -3668,7 +3717,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
return CandidateSet.BestViableFunction(S, DeclLoc, Best);
}
-/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
+/// Attempt initialization by constructor (C++ [dcl.init]), which
/// enumerates the constructors of the initialized entity and performs overload
/// resolution to select the best.
/// \param DestType The destination class type.
@@ -3885,7 +3934,7 @@ static void TryValueInitialization(Sema &S,
InitializationSequence &Sequence,
InitListExpr *InitList = nullptr);
-/// \brief Attempt list initialization of a reference.
+/// Attempt list initialization of a reference.
static void TryReferenceListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -3959,7 +4008,7 @@ static void TryReferenceListInitialization(Sema &S,
}
}
-/// \brief Attempt list initialization (C++0x [dcl.init.list])
+/// Attempt list initialization (C++0x [dcl.init.list])
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4154,7 +4203,7 @@ static void TryListInitialization(Sema &S,
Sequence.AddListInitializationStep(DestType);
}
-/// \brief Try a reference initialization that involves calling a conversion
+/// Try a reference initialization that involves calling a conversion
/// function.
static OverloadingResult TryRefInitWithConversionFunction(
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
@@ -4183,9 +4232,11 @@ static OverloadingResult TryRefInitWithConversionFunction(
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
- // Determine whether we are allowed to call explicit constructors or
- // explicit conversion operators.
- bool AllowExplicit = Kind.AllowExplicit();
+ // Determine whether we are allowed to call explicit conversion operators.
+ // Note that none of [over.match.copy], [over.match.conv], nor
+ // [over.match.ref] permit an explicit constructor to be chosen when
+ // initializing a reference, not even for direct-initialization.
+ bool AllowExplicitCtors = false;
bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding();
const RecordType *T1RecordType = nullptr;
@@ -4201,7 +4252,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
continue;
if (!Info.Constructor->isInvalidDecl() &&
- Info.Constructor->isConvertingConstructor(AllowExplicit)) {
+ Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr,
@@ -4344,7 +4395,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
const InitializedEntity &Entity,
Expr *CurInitExpr);
-/// \brief Attempt reference initialization (C++0x [dcl.init.ref])
+/// Attempt reference initialization (C++0x [dcl.init.ref])
static void TryReferenceInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4371,13 +4422,13 @@ static void TryReferenceInitialization(Sema &S,
}
/// Determine whether an expression is a non-referenceable glvalue (one to
-/// which a reference can never bind). Attemting to bind a reference to
+/// which a reference can never bind). Attempting to bind a reference to
/// such a glvalue will always create a temporary.
static bool isNonReferenceableGLValue(Expr *E) {
return E->refersToBitField() || E->refersToVectorElement();
}
-/// \brief Reference initialization without resolving overloaded functions.
+/// Reference initialization without resolving overloaded functions.
static void TryReferenceInitializationCore(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4637,7 +4688,7 @@ static void TryReferenceInitializationCore(Sema &S,
Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
}
-/// \brief Attempt character array initialization from a string literal
+/// Attempt character array initialization from a string literal
/// (C++ [dcl.init.string], C99 6.7.8).
static void TryStringLiteralInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -4647,7 +4698,7 @@ static void TryStringLiteralInitialization(Sema &S,
Sequence.AddStringInitStep(Entity.getType());
}
-/// \brief Attempt value initialization (C++ [dcl.init]p7).
+/// Attempt value initialization (C++ [dcl.init]p7).
static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4725,7 +4776,7 @@ static void TryValueInitialization(Sema &S,
Sequence.AddZeroInitializationStep(Entity.getType());
}
-/// \brief Attempt default initialization (C++ [dcl.init]p6).
+/// Attempt default initialization (C++ [dcl.init]p6).
static void TryDefaultInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4764,7 +4815,7 @@ static void TryDefaultInitialization(Sema &S,
}
}
-/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]),
+/// Attempt a user-defined conversion between two types (C++ [dcl.init]),
/// which enumerates all conversion functions and performs overload resolution
/// to select the best.
static void TryUserDefinedConversion(Sema &S,
@@ -5043,7 +5094,7 @@ static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
<< src->getSourceRange();
}
-/// \brief Determine whether we have compatible array types for the
+/// Determine whether we have compatible array types for the
/// purposes of GNU by-copy array initialization.
static bool hasCompatibleArrayTypes(ASTContext &Context, const ArrayType *Dest,
const ArrayType *Source) {
@@ -5337,6 +5388,12 @@ void InitializationSequence::InitializeFrom(Sema &S,
case SIF_IncompatWideStringIntoWideChar:
SetFailed(FK_IncompatWideStringIntoWideChar);
return;
+ case SIF_PlainStringIntoUTF8Char:
+ SetFailed(FK_PlainStringIntoUTF8Char);
+ return;
+ case SIF_UTF8StringIntoPlainChar:
+ SetFailed(FK_UTF8StringIntoPlainChar);
+ return;
case SIF_Other:
break;
}
@@ -5582,6 +5639,7 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) {
return !Diagnose ? Sema::AA_Passing : Sema::AA_Passing_CFAudited;
case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_StmtExprResult: // FIXME: Not quite right.
return Sema::AA_Returning;
case InitializedEntity::EK_Temporary:
@@ -5604,13 +5662,14 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) {
llvm_unreachable("Invalid EntityKind!");
}
-/// \brief Whether we should bind a created object as a temporary when
+/// Whether we should bind a created object as a temporary when
/// initializing the given entity.
static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Member:
case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_StmtExprResult:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Base:
@@ -5635,11 +5694,12 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
llvm_unreachable("missed an InitializedEntity kind?");
}
-/// \brief Whether the given entity, when initialized with an object
+/// Whether the given entity, when initialized with an object
/// created for that initialization, requires destruction.
static bool shouldDestroyEntity(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_StmtExprResult:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
@@ -5666,11 +5726,12 @@ static bool shouldDestroyEntity(const InitializedEntity &Entity) {
llvm_unreachable("missed an InitializedEntity kind?");
}
-/// \brief Get the location at which initialization diagnostics should appear.
+/// Get the location at which initialization diagnostics should appear.
static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
Expr *Initializer) {
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_StmtExprResult:
return Entity.getReturnLoc();
case InitializedEntity::EK_Exception:
@@ -5702,7 +5763,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
llvm_unreachable("missed an InitializedEntity kind?");
}
-/// \brief Make a (potentially elidable) temporary copy of the object
+/// Make a (potentially elidable) temporary copy of the object
/// provided by the given initializer by calling the appropriate copy
/// constructor.
///
@@ -5867,7 +5928,7 @@ static ExprResult CopyObject(Sema &S,
return CurInit;
}
-/// \brief Check whether elidable copy construction for binding a reference to
+/// Check whether elidable copy construction for binding a reference to
/// a temporary would have succeeded if we were building in C++98 mode, for
/// -Wc++98-compat.
static void CheckCXX98CompatAccessibleCopy(Sema &S,
@@ -6031,10 +6092,7 @@ PerformConstructorInitialization(Sema &S,
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
if (!TSInfo)
TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc);
- SourceRange ParenOrBraceRange =
- (Kind.getKind() == InitializationKind::IK_DirectList)
- ? SourceRange(LBraceLoc, RBraceLoc)
- : Kind.getParenRange();
+ SourceRange ParenOrBraceRange = Kind.getParenOrBraceRange();
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(
Step.Function.FoundDecl.getDecl())) {
@@ -6068,7 +6126,7 @@ PerformConstructorInitialization(Sema &S,
if (IsListInitialization)
ParenOrBraceRange = SourceRange(LBraceLoc, RBraceLoc);
else if (Kind.getKind() == InitializationKind::IK_Direct)
- ParenOrBraceRange = Kind.getParenRange();
+ ParenOrBraceRange = Kind.getParenOrBraceRange();
// If the entity allows NRVO, mark the construction as elidable
// unconditionally.
@@ -6109,90 +6167,96 @@ PerformConstructorInitialization(Sema &S,
return CurInit;
}
-/// Determine whether the specified InitializedEntity definitely has a lifetime
-/// longer than the current full-expression. Conservatively returns false if
-/// it's unclear.
-static bool
-InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
- const InitializedEntity *Top = &Entity;
- while (Top->getParent())
- Top = Top->getParent();
-
- switch (Top->getKind()) {
- case InitializedEntity::EK_Variable:
- case InitializedEntity::EK_Result:
- case InitializedEntity::EK_Exception:
- case InitializedEntity::EK_Member:
- case InitializedEntity::EK_Binding:
- case InitializedEntity::EK_New:
- case InitializedEntity::EK_Base:
- case InitializedEntity::EK_Delegating:
- return true;
-
- case InitializedEntity::EK_ArrayElement:
- case InitializedEntity::EK_VectorElement:
- case InitializedEntity::EK_BlockElement:
- case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
- case InitializedEntity::EK_ComplexElement:
- // Could not determine what the full initialization is. Assume it might not
- // outlive the full-expression.
- 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;
- }
-
- llvm_unreachable("unknown entity kind");
+namespace {
+enum LifetimeKind {
+ /// The lifetime of a temporary bound to this entity ends at the end of the
+ /// full-expression, and that's (probably) fine.
+ LK_FullExpression,
+
+ /// The lifetime of a temporary bound to this entity is extended to the
+ /// lifeitme of the entity itself.
+ LK_Extended,
+
+ /// The lifetime of a temporary bound to this entity probably ends too soon,
+ /// because the entity is allocated in a new-expression.
+ LK_New,
+
+ /// The lifetime of a temporary bound to this entity ends too soon, because
+ /// the entity is a return object.
+ LK_Return,
+
+ /// The lifetime of a temporary bound to this entity ends too soon, because
+ /// the entity is the result of a statement expression.
+ LK_StmtExprResult,
+
+ /// This is a mem-initializer: if it would extend a temporary (other than via
+ /// a default member initializer), the program is ill-formed.
+ LK_MemInitializer,
+};
+using LifetimeResult =
+ llvm::PointerIntPair<const InitializedEntity *, 3, LifetimeKind>;
}
/// 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 InitializedEntity *getEntityForTemporaryLifetimeExtension(
+static LifetimeResult getEntityLifetime(
const InitializedEntity *Entity,
- const InitializedEntity *FallbackDecl = nullptr) {
+ const InitializedEntity *InitField = nullptr) {
// C++11 [class.temporary]p5:
switch (Entity->getKind()) {
case InitializedEntity::EK_Variable:
// The temporary [...] persists for the lifetime of the reference
- return Entity;
+ return {Entity, LK_Extended};
case InitializedEntity::EK_Member:
// For subobjects, we look at the complete object.
if (Entity->getParent())
- return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
- Entity);
+ return getEntityLifetime(Entity->getParent(), Entity);
// except:
- // -- A temporary bound to a reference member in a constructor's
- // ctor-initializer persists until the constructor exits.
- return Entity;
+ // C++17 [class.base.init]p8:
+ // A temporary expression bound to a reference member in a
+ // mem-initializer is ill-formed.
+ // C++17 [class.base.init]p11:
+ // A temporary expression bound to a reference member from a
+ // default member initializer is ill-formed.
+ //
+ // The context of p11 and its example suggest that it's only the use of a
+ // default member initializer from a constructor that makes the program
+ // ill-formed, not its mere existence, and that it can even be used by
+ // aggregate initialization.
+ return {Entity, Entity->isDefaultMemberInitializer() ? LK_Extended
+ : LK_MemInitializer};
case InitializedEntity::EK_Binding:
// Per [dcl.decomp]p3, the binding is treated as a variable of reference
// type.
- return Entity;
+ return {Entity, LK_Extended};
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.
+ return {nullptr, LK_FullExpression};
+
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.
+ return {nullptr, LK_Return};
+
+ case InitializedEntity::EK_StmtExprResult:
+ // FIXME: Should we lifetime-extend through the result of a statement
+ // expression?
+ return {nullptr, LK_StmtExprResult};
+
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 nullptr;
+ return {nullptr, LK_New};
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_CompoundLiteralInit:
@@ -6200,56 +6264,122 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
// 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 nullptr;
+ return {nullptr, LK_FullExpression};
case InitializedEntity::EK_ArrayElement:
// For subobjects, we look at the complete object.
- return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
- FallbackDecl);
+ return getEntityLifetime(Entity->getParent(), InitField);
case InitializedEntity::EK_Base:
// For subobjects, we look at the complete object.
if (Entity->getParent())
- return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
- Entity);
- LLVM_FALLTHROUGH;
+ return getEntityLifetime(Entity->getParent(), InitField);
+ return {InitField, LK_MemInitializer};
+
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;
+ // In this case, use the outermost field decl as the context.
+ return {InitField, LK_MemInitializer};
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
- case InitializedEntity::EK_Exception:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
- return nullptr;
+ return {nullptr, LK_FullExpression};
+
+ case InitializedEntity::EK_Exception:
+ // FIXME: Can we diagnose lifetime problems with exceptions?
+ return {nullptr, LK_FullExpression};
}
llvm_unreachable("unknown entity kind");
}
-static void performLifetimeExtension(Expr *Init,
- const InitializedEntity *ExtendingEntity);
+namespace {
+enum ReferenceKind {
+ /// Lifetime would be extended by a reference binding to a temporary.
+ RK_ReferenceBinding,
+ /// Lifetime would be extended by a std::initializer_list object binding to
+ /// its backing array.
+ RK_StdInitializerList,
+};
+
+/// A temporary or local variable. This will be one of:
+/// * A MaterializeTemporaryExpr.
+/// * A DeclRefExpr whose declaration is a local.
+/// * An AddrLabelExpr.
+/// * A BlockExpr for a block with captures.
+using Local = Expr*;
+
+/// Expressions we stepped over when looking for the local state. Any steps
+/// that would inhibit lifetime extension or take us out of subexpressions of
+/// the initializer are included.
+struct IndirectLocalPathEntry {
+ enum EntryKind {
+ DefaultInit,
+ AddressOf,
+ VarInit,
+ LValToRVal,
+ } Kind;
+ Expr *E;
+ Decl *D = nullptr;
+ IndirectLocalPathEntry() {}
+ IndirectLocalPathEntry(EntryKind K, Expr *E) : Kind(K), E(E) {}
+ IndirectLocalPathEntry(EntryKind K, Expr *E, Decl *D) : Kind(K), E(E), D(D) {}
+};
+
+using IndirectLocalPath = llvm::SmallVectorImpl<IndirectLocalPathEntry>;
+
+struct RevertToOldSizeRAII {
+ IndirectLocalPath &Path;
+ unsigned OldSize = Path.size();
+ RevertToOldSizeRAII(IndirectLocalPath &Path) : Path(Path) {}
+ ~RevertToOldSizeRAII() { Path.resize(OldSize); }
+};
+
+using LocalVisitor = llvm::function_ref<bool(IndirectLocalPath &Path, Local L,
+ ReferenceKind RK)>;
+}
+
+static bool isVarOnPath(IndirectLocalPath &Path, VarDecl *VD) {
+ for (auto E : Path)
+ if (E.Kind == IndirectLocalPathEntry::VarInit && E.D == VD)
+ return true;
+ return false;
+}
+
+static bool pathContainsInit(IndirectLocalPath &Path) {
+ return std::any_of(Path.begin(), Path.end(), [=](IndirectLocalPathEntry E) {
+ return E.Kind == IndirectLocalPathEntry::DefaultInit ||
+ E.Kind == IndirectLocalPathEntry::VarInit;
+ });
+}
+
+static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
+ Expr *Init, LocalVisitor Visit,
+ bool RevisitSubinits);
+
+/// Visit the locals that would be reachable through a reference bound to the
+/// glvalue expression \c Init.
+static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
+ Expr *Init, ReferenceKind RK,
+ LocalVisitor Visit) {
+ RevertToOldSizeRAII RAII(Path);
-/// 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 InitializedEntity *ExtendingEntity) {
// Walk past any constructs which we can lifetime-extend across.
Expr *Old;
do {
Old = Init;
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
+ Init = EWC->getSubExpr();
+
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
- if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
- // This is just redundant braces around an initializer. Step over it.
+ // If this is just redundant braces around an initializer, step over it.
+ if (ILE->isTransparent())
Init = ILE->getInit(0);
- }
}
// Step over any subobject adjustments; we may have a materialized
@@ -6263,43 +6393,134 @@ performReferenceExtension(Expr *Init,
Init = CE->getSubExpr();
// Per the current approach for DR1299, look through array element access
- // when performing lifetime extension.
- if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init))
+ // on array glvalues when performing lifetime extension.
+ if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init)) {
Init = ASE->getBase();
+ auto *ICE = dyn_cast<ImplicitCastExpr>(Init);
+ if (ICE && ICE->getCastKind() == CK_ArrayToPointerDecay)
+ Init = ICE->getSubExpr();
+ else
+ // We can't lifetime extend through this but we might still find some
+ // retained temporaries.
+ return visitLocalsRetainedByInitializer(Path, Init, Visit, true);
+ }
+
+ // Step into CXXDefaultInitExprs so we can diagnose cases where a
+ // constructor inherits one as an implicit mem-initializer.
+ if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
+ Path.push_back(
+ {IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
+ Init = DIE->getExpr();
+ }
} 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(ExtendingEntity->getDecl(),
- ExtendingEntity->allocateManglingNumber());
- performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingEntity);
- return true;
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
+ if (Visit(Path, Local(MTE), RK))
+ visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit,
+ true);
+ }
+
+ switch (Init->getStmtClass()) {
+ case Stmt::DeclRefExprClass: {
+ // If we find the name of a local non-reference parameter, we could have a
+ // lifetime problem.
+ auto *DRE = cast<DeclRefExpr>(Init);
+ auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
+ if (VD && VD->hasLocalStorage() &&
+ !DRE->refersToEnclosingVariableOrCapture()) {
+ if (!VD->getType()->isReferenceType()) {
+ Visit(Path, Local(DRE), RK);
+ } else if (isa<ParmVarDecl>(DRE->getDecl())) {
+ // The lifetime of a reference parameter is unknown; assume it's OK
+ // for now.
+ break;
+ } else if (VD->getInit() && !isVarOnPath(Path, VD)) {
+ Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
+ visitLocalsRetainedByReferenceBinding(Path, VD->getInit(),
+ RK_ReferenceBinding, Visit);
+ }
+ }
+ break;
}
- return false;
+ case Stmt::UnaryOperatorClass: {
+ // The only unary operator that make sense to handle here
+ // is Deref. All others don't resolve to a "name." This includes
+ // handling all sorts of rvalues passed to a unary operator.
+ const UnaryOperator *U = cast<UnaryOperator>(Init);
+ if (U->getOpcode() == UO_Deref)
+ visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true);
+ break;
+ }
+
+ case Stmt::OMPArraySectionExprClass: {
+ visitLocalsRetainedByInitializer(
+ Path, cast<OMPArraySectionExpr>(Init)->getBase(), Visit, true);
+ break;
+ }
+
+ case Stmt::ConditionalOperatorClass:
+ case Stmt::BinaryConditionalOperatorClass: {
+ auto *C = cast<AbstractConditionalOperator>(Init);
+ if (!C->getTrueExpr()->getType()->isVoidType())
+ visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit);
+ if (!C->getFalseExpr()->getType()->isVoidType())
+ visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit);
+ break;
+ }
+
+ // FIXME: Visit the left-hand side of an -> or ->*.
+
+ default:
+ break;
+ }
}
-/// Update a prvalue expression that is going to be materialized as a
-/// lifetime-extended temporary.
-static void performLifetimeExtension(Expr *Init,
- const InitializedEntity *ExtendingEntity) {
+/// Visit the locals that would be reachable through an object initialized by
+/// the prvalue expression \c Init.
+static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
+ Expr *Init, LocalVisitor Visit,
+ bool RevisitSubinits) {
+ RevertToOldSizeRAII RAII(Path);
+
+ // Step into CXXDefaultInitExprs so we can diagnose cases where a
+ // constructor inherits one as an implicit mem-initializer.
+ if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
+ Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
+ Init = DIE->getExpr();
+ }
+
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
+ Init = EWC->getSubExpr();
+
// Dig out the expression which constructs the extended temporary.
Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
Init = BTE->getSubExpr();
- if (CXXStdInitializerListExpr *ILE =
- dyn_cast<CXXStdInitializerListExpr>(Init)) {
- performReferenceExtension(ILE->getSubExpr(), ExtendingEntity);
- return;
- }
+ // C++17 [dcl.init.list]p6:
+ // initializing an initializer_list object from the array extends the
+ // lifetime of the array exactly like binding a reference to a temporary.
+ if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init))
+ return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(),
+ RK_StdInitializerList, Visit);
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ // We already visited the elements of this initializer list while
+ // performing the initialization. Don't visit them again unless we've
+ // changed the lifetime of the initialized entity.
+ if (!RevisitSubinits)
+ return;
+
+ if (ILE->isTransparent())
+ return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit,
+ RevisitSubinits);
+
if (ILE->getType()->isArrayType()) {
for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
- performLifetimeExtension(ILE->getInit(I), ExtendingEntity);
+ visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit,
+ RevisitSubinits);
return;
}
@@ -6311,7 +6532,8 @@ static void performLifetimeExtension(Expr *Init,
// bound to temporaries, those temporaries are also lifetime-extended.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
- performReferenceExtension(ILE->getInit(0), ExtendingEntity);
+ visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0),
+ RK_ReferenceBinding, Visit);
else {
unsigned Index = 0;
for (const auto *I : RD->fields()) {
@@ -6321,51 +6543,365 @@ static void performLifetimeExtension(Expr *Init,
continue;
Expr *SubInit = ILE->getInit(Index);
if (I->getType()->isReferenceType())
- performReferenceExtension(SubInit, ExtendingEntity);
- 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,
+ visitLocalsRetainedByReferenceBinding(Path, SubInit,
+ RK_ReferenceBinding, Visit);
+ else
+ // This might be either aggregate-initialization of a member or
+ // initialization of a std::initializer_list object. Regardless,
// we should recursively lifetime-extend that initializer.
- performLifetimeExtension(SubInit, ExtendingEntity);
+ visitLocalsRetainedByInitializer(Path, SubInit, Visit,
+ RevisitSubinits);
++Index;
}
}
}
+ return;
}
-}
-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;
+ // Step over value-preserving rvalue casts.
+ while (auto *CE = dyn_cast<CastExpr>(Init)) {
+ switch (CE->getCastKind()) {
+ case CK_LValueToRValue:
+ // If we can match the lvalue to a const object, we can look at its
+ // initializer.
+ Path.push_back({IndirectLocalPathEntry::LValToRVal, CE});
+ return visitLocalsRetainedByReferenceBinding(
+ Path, Init, RK_ReferenceBinding,
+ [&](IndirectLocalPath &Path, Local L, ReferenceKind RK) -> bool {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(L)) {
+ auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
+ if (VD && VD->getType().isConstQualified() && VD->getInit()) {
+ Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
+ visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true);
+ }
+ } else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
+ if (MTE->getType().isConstQualified())
+ visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(),
+ Visit, true);
+ }
+ return false;
+ });
+
+ // We assume that objects can be retained by pointers cast to integers,
+ // but not if the integer is cast to floating-point type or to _Complex.
+ // We assume that casts to 'bool' do not preserve enough information to
+ // retain a local object.
+ case CK_NoOp:
+ case CK_BitCast:
+ case CK_BaseToDerived:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_IntegralToPointer:
+ case CK_PointerToIntegral:
+ case CK_VectorSplat:
+ case CK_IntegralCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_AddressSpaceConversion:
+ break;
+
+ case CK_ArrayToPointerDecay:
+ // Model array-to-pointer decay as taking the address of the array
+ // lvalue.
+ Path.push_back({IndirectLocalPathEntry::AddressOf, CE});
+ return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(),
+ RK_ReferenceBinding, Visit);
+
+ default:
return;
}
- bool IsSubobjectMember = false;
- for (const InitializedEntity *Ent = Entity.getParent(); Ent;
- Ent = Ent->getParent()) {
- if (Ent->getKind() != InitializedEntity::EK_Base) {
- IsSubobjectMember = true;
+ Init = CE->getSubExpr();
+ }
+
+ Init = Init->IgnoreParens();
+ switch (Init->getStmtClass()) {
+ case Stmt::UnaryOperatorClass: {
+ auto *UO = cast<UnaryOperator>(Init);
+ // If the initializer is the address of a local, we could have a lifetime
+ // problem.
+ if (UO->getOpcode() == UO_AddrOf) {
+ // If this is &rvalue, then it's ill-formed and we have already diagnosed
+ // it. Don't produce a redundant warning about the lifetime of the
+ // temporary.
+ if (isa<MaterializeTemporaryExpr>(UO->getSubExpr()))
+ return;
+
+ Path.push_back({IndirectLocalPathEntry::AddressOf, UO});
+ visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(),
+ RK_ReferenceBinding, Visit);
+ }
+ break;
+ }
+
+ case Stmt::BinaryOperatorClass: {
+ // Handle pointer arithmetic.
+ auto *BO = cast<BinaryOperator>(Init);
+ BinaryOperatorKind BOK = BO->getOpcode();
+ if (!BO->getType()->isPointerType() || (BOK != BO_Add && BOK != BO_Sub))
+ break;
+
+ if (BO->getLHS()->getType()->isPointerType())
+ visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true);
+ else if (BO->getRHS()->getType()->isPointerType())
+ visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true);
+ break;
+ }
+
+ case Stmt::ConditionalOperatorClass:
+ case Stmt::BinaryConditionalOperatorClass: {
+ auto *C = cast<AbstractConditionalOperator>(Init);
+ // In C++, we can have a throw-expression operand, which has 'void' type
+ // and isn't interesting from a lifetime perspective.
+ if (!C->getTrueExpr()->getType()->isVoidType())
+ visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true);
+ if (!C->getFalseExpr()->getType()->isVoidType())
+ visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true);
+ break;
+ }
+
+ case Stmt::BlockExprClass:
+ if (cast<BlockExpr>(Init)->getBlockDecl()->hasCaptures()) {
+ // This is a local block, whose lifetime is that of the function.
+ Visit(Path, Local(cast<BlockExpr>(Init)), RK_ReferenceBinding);
+ }
+ break;
+
+ case Stmt::AddrLabelExprClass:
+ // We want to warn if the address of a label would escape the function.
+ Visit(Path, Local(cast<AddrLabelExpr>(Init)), RK_ReferenceBinding);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/// Determine whether this is an indirect path to a temporary that we are
+/// supposed to lifetime-extend along (but don't).
+static bool shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
+ for (auto Elem : Path) {
+ if (Elem.Kind != IndirectLocalPathEntry::DefaultInit)
+ return false;
+ }
+ return true;
+}
+
+/// Find the range for the first interesting entry in the path at or after I.
+static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
+ Expr *E) {
+ for (unsigned N = Path.size(); I != N; ++I) {
+ switch (Path[I].Kind) {
+ case IndirectLocalPathEntry::AddressOf:
+ case IndirectLocalPathEntry::LValToRVal:
+ // These exist primarily to mark the path as not permitting or
+ // supporting lifetime extension.
+ break;
+
+ case IndirectLocalPathEntry::DefaultInit:
+ case IndirectLocalPathEntry::VarInit:
+ return Path[I].E->getSourceRange();
+ }
+ }
+ return E->getSourceRange();
+}
+
+void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
+ Expr *Init) {
+ LifetimeResult LR = getEntityLifetime(&Entity);
+ LifetimeKind LK = LR.getInt();
+ const InitializedEntity *ExtendingEntity = LR.getPointer();
+
+ // If this entity doesn't have an interesting lifetime, don't bother looking
+ // for temporaries within its initializer.
+ if (LK == LK_FullExpression)
+ return;
+
+ auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L,
+ ReferenceKind RK) -> bool {
+ SourceRange DiagRange = nextPathEntryRange(Path, 0, L);
+ SourceLocation DiagLoc = DiagRange.getBegin();
+
+ switch (LK) {
+ case LK_FullExpression:
+ llvm_unreachable("already handled this");
+
+ case LK_Extended: {
+ auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
+ if (!MTE) {
+ // The initialized entity has lifetime beyond the full-expression,
+ // and the local entity does too, so don't warn.
+ //
+ // FIXME: We should consider warning if a static / thread storage
+ // duration variable retains an automatic storage duration local.
+ return false;
+ }
+
+ // Lifetime-extend the temporary.
+ if (Path.empty()) {
+ // Update the storage duration of the materialized temporary.
+ // FIXME: Rebuild the expression instead of mutating it.
+ MTE->setExtendingDecl(ExtendingEntity->getDecl(),
+ ExtendingEntity->allocateManglingNumber());
+ // Also visit the temporaries lifetime-extended by this initializer.
+ return true;
+ }
+
+ if (shouldLifetimeExtendThroughPath(Path)) {
+ // We're supposed to lifetime-extend the temporary along this path (per
+ // the resolution of DR1815), but we don't support that yet.
+ //
+ // FIXME: Properly handle this situation. Perhaps the easiest approach
+ // would be to clone the initializer expression on each use that would
+ // lifetime extend its temporaries.
+ Diag(DiagLoc, diag::warn_unsupported_lifetime_extension)
+ << RK << DiagRange;
+ } else {
+ // If the path goes through the initialization of a variable or field,
+ // it can't possibly reach a temporary created in this full-expression.
+ // We will have already diagnosed any problems with the initializer.
+ if (pathContainsInit(Path))
+ return false;
+
+ Diag(DiagLoc, diag::warn_dangling_variable)
+ << RK << !Entity.getParent() << ExtendingEntity->getDecl()
+ << Init->isGLValue() << DiagRange;
+ }
+ break;
+ }
+
+ case LK_MemInitializer: {
+ if (isa<MaterializeTemporaryExpr>(L)) {
+ // Under C++ DR1696, if a mem-initializer (or a default member
+ // initializer used by the absence of one) would lifetime-extend a
+ // temporary, the program is ill-formed.
+ if (auto *ExtendingDecl =
+ ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
+ bool IsSubobjectMember = ExtendingEntity != &Entity;
+ Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path)
+ ? diag::err_dangling_member
+ : diag::warn_dangling_member)
+ << ExtendingDecl << IsSubobjectMember << RK << DiagRange;
+ // Don't bother adding a note pointing to the field if we're inside
+ // its default member initializer; our primary diagnostic points to
+ // the same place in that case.
+ if (Path.empty() ||
+ Path.back().Kind != IndirectLocalPathEntry::DefaultInit) {
+ Diag(ExtendingDecl->getLocation(),
+ diag::note_lifetime_extending_member_declared_here)
+ << RK << IsSubobjectMember;
+ }
+ } else {
+ // We have a mem-initializer but no particular field within it; this
+ // is either a base class or a delegating initializer directly
+ // initializing the base-class from something that doesn't live long
+ // enough.
+ //
+ // FIXME: Warn on this.
+ return false;
+ }
+ } else {
+ // Paths via a default initializer can only occur during error recovery
+ // (there's no other way that a default initializer can refer to a
+ // local). Don't produce a bogus warning on those cases.
+ if (pathContainsInit(Path))
+ return false;
+
+ auto *DRE = dyn_cast<DeclRefExpr>(L);
+ auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
+ if (!VD) {
+ // A member was initialized to a local block.
+ // FIXME: Warn on this.
+ return false;
+ }
+
+ if (auto *Member =
+ ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
+ bool IsPointer = Member->getType()->isAnyPointerType();
+ Diag(DiagLoc, IsPointer ? diag::warn_init_ptr_member_to_parameter_addr
+ : diag::warn_bind_ref_member_to_parameter)
+ << Member << VD << isa<ParmVarDecl>(VD) << DiagRange;
+ Diag(Member->getLocation(),
+ diag::note_ref_or_ptr_member_declared_here)
+ << (unsigned)IsPointer;
+ }
+ }
+ break;
+ }
+
+ case LK_New:
+ if (isa<MaterializeTemporaryExpr>(L)) {
+ Diag(DiagLoc, RK == RK_ReferenceBinding
+ ? diag::warn_new_dangling_reference
+ : diag::warn_new_dangling_initializer_list)
+ << !Entity.getParent() << DiagRange;
+ } else {
+ // We can't determine if the allocation outlives the local declaration.
+ return false;
+ }
+ break;
+
+ case LK_Return:
+ case LK_StmtExprResult:
+ if (auto *DRE = dyn_cast<DeclRefExpr>(L)) {
+ // We can't determine if the local variable outlives the statement
+ // expression.
+ if (LK == LK_StmtExprResult)
+ return false;
+ Diag(DiagLoc, diag::warn_ret_stack_addr_ref)
+ << Entity.getType()->isReferenceType() << DRE->getDecl()
+ << isa<ParmVarDecl>(DRE->getDecl()) << DiagRange;
+ } else if (isa<BlockExpr>(L)) {
+ Diag(DiagLoc, diag::err_ret_local_block) << DiagRange;
+ } else if (isa<AddrLabelExpr>(L)) {
+ Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange;
+ } else {
+ Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref)
+ << Entity.getType()->isReferenceType() << DiagRange;
+ }
+ break;
+ }
+
+ for (unsigned I = 0; I != Path.size(); ++I) {
+ auto Elem = Path[I];
+
+ switch (Elem.Kind) {
+ case IndirectLocalPathEntry::AddressOf:
+ case IndirectLocalPathEntry::LValToRVal:
+ // These exist primarily to mark the path as not permitting or
+ // supporting lifetime extension.
+ break;
+
+ case IndirectLocalPathEntry::DefaultInit: {
+ auto *FD = cast<FieldDecl>(Elem.D);
+ Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer)
+ << FD << nextPathEntryRange(Path, I + 1, L);
+ break;
+ }
+
+ case IndirectLocalPathEntry::VarInit:
+ const VarDecl *VD = cast<VarDecl>(Elem.D);
+ Diag(VD->getLocation(), diag::note_local_var_initializer)
+ << VD->getType()->isReferenceType() << VD->getDeclName()
+ << nextPathEntryRange(Path, I + 1, L);
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;
- }
+
+ // We didn't lifetime-extend, so don't go any further; we don't need more
+ // warnings or errors on inner temporaries within this one's initializer.
+ return false;
+ };
+
+ llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
+ if (Init->isGLValue())
+ visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,
+ TemporaryVisitor);
+ else
+ visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false);
}
static void DiagnoseNarrowingInInitList(Sema &S,
@@ -6402,13 +6938,7 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
// Find the std::move call and get the argument.
const CallExpr *CE = dyn_cast<CallExpr>(InitExpr->IgnoreParens());
- if (!CE || CE->getNumArgs() != 1)
- return;
-
- const FunctionDecl *MoveFunction = CE->getDirectCallee();
- if (!MoveFunction || !MoveFunction->isInStdNamespace() ||
- !MoveFunction->getIdentifier() ||
- !MoveFunction->getIdentifier()->isStr("move"))
+ if (!CE || !CE->isCallToStdMove())
return;
const Expr *Arg = CE->getArg(0)->IgnoreImplicit();
@@ -6465,7 +6995,7 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
// macro only if it is at the beginning of the macro.
while (ArgLoc.isMacroID() &&
S.getSourceManager().isAtStartOfImmediateMacroExpansion(ArgLoc)) {
- ArgLoc = S.getSourceManager().getImmediateExpansionRange(ArgLoc).first;
+ ArgLoc = S.getSourceManager().getImmediateExpansionRange(ArgLoc).getBegin();
}
if (LParen.isMacroID())
@@ -6594,7 +7124,7 @@ InitializationSequence::Perform(Sema &S,
if (Kind.getKind() == InitializationKind::IK_Direct &&
!Kind.isExplicitCast()) {
// Rebuild the ParenListExpr.
- SourceRange ParenRange = Kind.getParenRange();
+ SourceRange ParenRange = Kind.getParenOrBraceRange();
return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(),
Args);
}
@@ -6633,20 +7163,6 @@ InitializationSequence::Perform(Sema &S,
return ExprError();
}
- // Diagnose cases where we initialize a pointer to an array temporary, and the
- // pointer obviously outlives the temporary.
- if (Args.size() == 1 && Args[0]->getType()->isArrayType() &&
- Entity.getType()->isPointerType() &&
- InitializedEntityOutlivesFullExpression(Entity)) {
- const Expr *Init = Args[0]->skipRValueSubobjectAdjustments();
- if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init))
- Init = MTE->GetTemporaryExpr();
- Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context);
- if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary)
- S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay)
- << Init->getSourceRange();
- }
-
QualType DestType = Entity.getType().getNonReferenceType();
// FIXME: Ugly hack around the fact that Entity.getType() is not
// the same as Entity.getDecl()->getType() in cases involving type merging,
@@ -6797,16 +7313,6 @@ InitializationSequence::Perform(Sema &S,
}
}
- // 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 InitializedEntity *ExtendingEntity =
- getEntityForTemporaryLifetimeExtension(&Entity))
- if (performReferenceExtension(CurInit.get(), ExtendingEntity))
- warnOnLifetimeExtension(S, Entity, CurInit.get(),
- /*IsInitializerList=*/false,
- ExtendingEntity->getDecl());
-
CheckForNullPointerDereference(S, CurInit.get());
break;
@@ -6821,23 +7327,13 @@ InitializationSequence::Perform(Sema &S,
// Materialize the temporary into memory.
MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
Step->Type, CurInit.get(), Entity.getType()->isLValueReferenceType());
-
- // Maybe lifetime-extend the temporary's subobjects to match the
- // entity's lifetime.
- if (const InitializedEntity *ExtendingEntity =
- getEntityForTemporaryLifetimeExtension(&Entity))
- if (performReferenceExtension(MTE, ExtendingEntity))
- warnOnLifetimeExtension(S, Entity, CurInit.get(),
- /*IsInitializerList=*/false,
- ExtendingEntity->getDecl());
+ CurInit = MTE;
// If we're extending this temporary to automatic storage duration -- we
// need to register its cleanup during the full-expression's cleanups.
if (MTE->getStorageDuration() == SD_Automatic &&
MTE->getType().isDestructedType())
S.Cleanup.setExprNeedsCleanups(true);
-
- CurInit = MTE;
break;
}
@@ -6910,16 +7406,6 @@ InitializationSequence::Perform(Sema &S,
if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()))
return ExprError();
- // FIXME: Should we move this initialization into a separate
- // derived-to-base conversion? I believe the answer is "no", because
- // we don't want to turn off access control here for c-style casts.
- CurInit = S.PerformObjectArgumentInitialization(CurInit.get(),
- /*Qualifier=*/nullptr,
- FoundFn, Conversion);
- if (CurInit.isInvalid())
- return ExprError();
-
- // Build the actual call to the conversion function.
CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion,
HadMultipleCandidates);
if (CurInit.isInvalid())
@@ -7114,14 +7600,17 @@ InitializationSequence::Perform(Sema &S,
bool IsStdInitListInit =
Step->Kind == SK_StdInitializerListConstructorCall;
Expr *Source = CurInit.get();
+ SourceRange Range = Kind.hasParenOrBraceRange()
+ ? Kind.getParenOrBraceRange()
+ : SourceRange();
CurInit = PerformConstructorInitialization(
S, UseTemporary ? TempEntity : Entity, Kind,
Source ? MultiExprArg(Source) : Args, *Step,
ConstructorInitRequiresZeroInit,
/*IsListInitialization*/ IsStdInitListInit,
/*IsStdInitListInitialization*/ IsStdInitListInit,
- /*LBraceLoc*/ SourceLocation(),
- /*RBraceLoc*/ SourceLocation());
+ /*LBraceLoc*/ Range.getBegin(),
+ /*RBraceLoc*/ Range.getEnd());
break;
}
@@ -7277,15 +7766,6 @@ InitializationSequence::Perform(Sema &S,
CurInit.get()->getType(), CurInit.get(),
/*BoundToLvalueReference=*/false);
- // Maybe lifetime-extend the array temporary's subobjects to match the
- // entity's lifetime.
- if (const InitializedEntity *ExtendingEntity =
- getEntityForTemporaryLifetimeExtension(&Entity))
- if (performReferenceExtension(MTE, ExtendingEntity))
- warnOnLifetimeExtension(S, Entity, CurInit.get(),
- /*IsInitializerList=*/true,
- ExtendingEntity->getDecl());
-
// Wrap it in a construction of a std::initializer_list<T>.
CurInit = new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE);
@@ -7407,6 +7887,11 @@ InitializationSequence::Perform(Sema &S,
}
}
+ // Check whether the initializer has a shorter lifetime than the initialized
+ // entity, and if not, either lifetime-extend or warn as appropriate.
+ if (auto *Init = CurInit.get())
+ S.checkInitializerLifetime(Entity, Init);
+
// Diagnose non-fatal problems with the completed initialization.
if (Entity.getKind() == InitializedEntity::EK_Member &&
cast<FieldDecl>(Entity.getDecl())->isBitField())
@@ -7524,6 +8009,19 @@ bool InitializationSequence::Diagnose(Sema &S,
if (!Failed())
return false;
+ // When we want to diagnose only one element of a braced-init-list,
+ // we need to factor it out.
+ Expr *OnlyArg;
+ if (Args.size() == 1) {
+ auto *List = dyn_cast<InitListExpr>(Args[0]);
+ if (List && List->getNumInits() == 1)
+ OnlyArg = List->getInit(0);
+ else
+ OnlyArg = Args[0];
+ }
+ else
+ OnlyArg = nullptr;
+
QualType DestType = Entity.getType();
switch (Failure) {
case FK_TooManyInitsForReference:
@@ -7566,6 +8064,17 @@ bool InitializationSequence::Diagnose(Sema &S,
S.Diag(Kind.getLocation(),
diag::err_array_init_incompat_wide_string_into_wchar);
break;
+ case FK_PlainStringIntoUTF8Char:
+ S.Diag(Kind.getLocation(),
+ diag::err_array_init_plain_string_into_char8_t);
+ S.Diag(Args.front()->getLocStart(),
+ diag::note_array_init_plain_string_into_char8_t)
+ << FixItHint::CreateInsertion(Args.front()->getLocStart(), "u8");
+ break;
+ case FK_UTF8StringIntoPlainChar:
+ S.Diag(Kind.getLocation(),
+ diag::err_array_init_utf8_string_into_char);
+ break;
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
S.Diag(Kind.getLocation(),
@@ -7573,7 +8082,7 @@ bool InitializationSequence::Diagnose(Sema &S,
? diag::err_array_init_different_type
: diag::err_array_init_non_constant_array))
<< DestType.getNonReferenceType()
- << Args[0]->getType()
+ << OnlyArg->getType()
<< Args[0]->getSourceRange();
break;
@@ -7584,7 +8093,7 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_AddressOfOverloadFailed: {
DeclAccessPair Found;
- S.ResolveAddressOfOverloadedFunction(Args[0],
+ S.ResolveAddressOfOverloadedFunction(OnlyArg,
DestType.getNonReferenceType(),
true,
Found);
@@ -7592,9 +8101,9 @@ bool InitializationSequence::Diagnose(Sema &S,
}
case FK_AddressOfUnaddressableFunction: {
- auto *FD = cast<FunctionDecl>(cast<DeclRefExpr>(Args[0])->getDecl());
+ auto *FD = cast<FunctionDecl>(cast<DeclRefExpr>(OnlyArg)->getDecl());
S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
- Args[0]->getLocStart());
+ OnlyArg->getLocStart());
break;
}
@@ -7604,11 +8113,11 @@ bool InitializationSequence::Diagnose(Sema &S,
case OR_Ambiguous:
if (Failure == FK_UserConversionOverloadFailed)
S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
- << Args[0]->getType() << DestType
+ << OnlyArg->getType() << DestType
<< Args[0]->getSourceRange();
else
S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous)
- << DestType << Args[0]->getType()
+ << DestType << OnlyArg->getType()
<< Args[0]->getSourceRange();
FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args);
@@ -7618,10 +8127,10 @@ bool InitializationSequence::Diagnose(Sema &S,
if (!S.RequireCompleteType(Kind.getLocation(),
DestType.getNonReferenceType(),
diag::err_typecheck_nonviable_condition_incomplete,
- Args[0]->getType(), Args[0]->getSourceRange()))
+ OnlyArg->getType(), Args[0]->getSourceRange()))
S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
<< (Entity.getKind() == InitializedEntity::EK_Result)
- << Args[0]->getType() << Args[0]->getSourceRange()
+ << OnlyArg->getType() << Args[0]->getSourceRange()
<< DestType.getNonReferenceType();
FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args);
@@ -7629,7 +8138,7 @@ bool InitializationSequence::Diagnose(Sema &S,
case OR_Deleted: {
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
- << Args[0]->getType() << DestType.getNonReferenceType()
+ << OnlyArg->getType() << DestType.getNonReferenceType()
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
@@ -7665,7 +8174,7 @@ bool InitializationSequence::Diagnose(Sema &S,
: diag::err_lvalue_reference_bind_to_unrelated)
<< DestType.getNonReferenceType().isVolatileQualified()
<< DestType.getNonReferenceType()
- << Args[0]->getType()
+ << OnlyArg->getType()
<< Args[0]->getSourceRange();
break;
@@ -7690,12 +8199,12 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_RValueReferenceBindingToLValue:
S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref)
- << DestType.getNonReferenceType() << Args[0]->getType()
+ << DestType.getNonReferenceType() << OnlyArg->getType()
<< Args[0]->getSourceRange();
break;
case FK_ReferenceInitDropsQualifiers: {
- QualType SourceType = Args[0]->getType();
+ QualType SourceType = OnlyArg->getType();
QualType NonRefType = DestType.getNonReferenceType();
Qualifiers DroppedQualifiers =
SourceType.getQualifiers() - NonRefType.getQualifiers();
@@ -7711,18 +8220,18 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_ReferenceInitFailed:
S.Diag(Kind.getLocation(), diag::err_reference_bind_failed)
<< DestType.getNonReferenceType()
- << Args[0]->isLValue()
- << Args[0]->getType()
+ << OnlyArg->isLValue()
+ << OnlyArg->getType()
<< Args[0]->getSourceRange();
emitBadConversionNotes(S, Entity, Args[0]);
break;
case FK_ConversionFailed: {
- QualType FromType = Args[0]->getType();
+ QualType FromType = OnlyArg->getType();
PartialDiagnostic PDiag = S.PDiag(diag::err_init_conversion_failed)
<< (int)Entity.getKind()
<< DestType
- << Args[0]->isLValue()
+ << OnlyArg->isLValue()
<< FromType
<< Args[0]->getSourceRange();
S.HandleFunctionTypeMismatch(PDiag, FromType, DestType);
@@ -7975,6 +8484,14 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "incompatible wide string into wide char array";
break;
+ case FK_PlainStringIntoUTF8Char:
+ OS << "plain string literal into char8_t array";
+ break;
+
+ case FK_UTF8StringIntoPlainChar:
+ OS << "u8 string literal into char array";
+ break;
+
case FK_ArrayTypeMismatch:
OS << "array type mismatch";
break;
@@ -8265,6 +8782,11 @@ void InitializationSequence::dump() const {
dump(llvm::errs());
}
+static bool NarrowingErrs(const LangOptions &L) {
+ return L.CPlusPlus11 &&
+ (!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015));
+}
+
static void DiagnoseNarrowingInInitList(Sema &S,
const ImplicitConversionSequence &ICS,
QualType PreNarrowingType,
@@ -8298,35 +8820,34 @@ static void DiagnoseNarrowingInInitList(Sema &S,
// This was a floating-to-integer conversion, which is always considered a
// 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
- : diag::ext_init_list_type_narrowing)
- << PostInit->getSourceRange()
- << PreNarrowingType.getLocalUnqualifiedType()
- << EntityType.getLocalUnqualifiedType();
+ S.Diag(PostInit->getLocStart(), NarrowingErrs(S.getLangOpts())
+ ? diag::ext_init_list_type_narrowing
+ : diag::warn_init_list_type_narrowing)
+ << PostInit->getSourceRange()
+ << PreNarrowingType.getLocalUnqualifiedType()
+ << EntityType.getLocalUnqualifiedType();
break;
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
- : diag::ext_init_list_constant_narrowing)
- << PostInit->getSourceRange()
- << ConstantValue.getAsString(S.getASTContext(), ConstantType)
- << EntityType.getLocalUnqualifiedType();
+ NarrowingErrs(S.getLangOpts())
+ ? diag::ext_init_list_constant_narrowing
+ : diag::warn_init_list_constant_narrowing)
+ << PostInit->getSourceRange()
+ << ConstantValue.getAsString(S.getASTContext(), ConstantType)
+ << EntityType.getLocalUnqualifiedType();
break;
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
- : diag::ext_init_list_variable_narrowing)
- << PostInit->getSourceRange()
- << PreNarrowingType.getLocalUnqualifiedType()
- << EntityType.getLocalUnqualifiedType();
+ NarrowingErrs(S.getLangOpts())
+ ? diag::ext_init_list_variable_narrowing
+ : diag::warn_init_list_variable_narrowing)
+ << PostInit->getSourceRange()
+ << PreNarrowingType.getLocalUnqualifiedType()
+ << EntityType.getLocalUnqualifiedType();
break;
}
@@ -8599,6 +9120,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
Expr *E = ListInit->getInit(0);
auto *RD = E->getType()->getAsCXXRecordDecl();
if (!isa<InitListExpr>(E) && RD &&
+ isCompleteType(Kind.getLocation(), E->getType()) &&
isOrIsDerivedFromSpecializationOf(RD, Template))
TryListConstructors = false;
}