summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaInit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r--lib/Sema/SemaInit.cpp296
1 files changed, 191 insertions, 105 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3ee5ec4a4929e..f006a677b6789 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -191,7 +191,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
if (SL->isPascal())
StrLength--;
}
-
+
// [dcl.init.string]p2
if (StrLength > CAT->getSize().getZExtValue())
S.Diag(Str->getLocStart(),
@@ -450,7 +450,7 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
IsInStd = true;
}
- if (IsInStd && llvm::StringSwitch<bool>(R->getName())
+ if (IsInStd && llvm::StringSwitch<bool>(R->getName())
.Cases("basic_string", "deque", "forward_list", true)
.Cases("list", "map", "multimap", "multiset", true)
.Cases("priority_queue", "queue", "set", "stack", true)
@@ -1578,7 +1578,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
T->getVectorKind() == VectorType::NeonPolyVector)) {
// The ability to use vector initializer lists is a GNU vector extension
// and is unrelated to the NEON intrinsics in arm_neon.h. On little
- // endian machines it works fine, however on big endian machines it
+ // endian machines it works fine, however on big endian machines it
// exhibits surprising behaviour:
//
// uint32x2_t x = {42, 64};
@@ -2225,7 +2225,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
SemaRef.Diag(D->getLocStart(),
diag::warn_subobject_initializer_overrides)
<< SourceRange(D->getLocStart(), DIE->getLocEnd());
-
+
SemaRef.Diag(ExistingInit->getLocStart(),
diag::note_previous_initializer)
<< /*FIXME:has side effects=*/0
@@ -3000,7 +3000,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_LambdaCapture:
return DeclarationName(Capture.VarID);
-
+
case EK_Result:
case EK_StmtExprResult:
case EK_Exception:
@@ -3653,13 +3653,13 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
CandidateSet, SuppressUserConversions);
else {
// C++ [over.match.copy]p1:
- // - When initializing a temporary to be bound to the first parameter
+ // - When initializing a temporary to be bound to the first parameter
// of a constructor [for type T] that takes a reference to possibly
// cv-qualified T as its first argument, called with a single
// argument in the context of direct-initialization, explicit
// conversion functions are also considered.
// FIXME: What if a constructor template instantiates to such a signature?
- bool AllowExplicitConv = AllowExplicit && !CopyInitializing &&
+ bool AllowExplicitConv = AllowExplicit && !CopyInitializing &&
Args.size() == 1 &&
hasCopyOrMoveCtorParam(S.Context, Info);
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
@@ -4226,7 +4226,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
(void)DerivedToBase;
(void)ObjCConversion;
(void)ObjCLifetimeConversion;
-
+
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -4646,7 +4646,7 @@ static void TryReferenceInitializationCore(Sema &S,
/*FIXME:InOverloadResolution=*/false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast(),
/*AllowObjCWritebackConversion=*/false);
-
+
if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
// this into an overloading ambiguity diagnostic. However, we need
@@ -4787,7 +4787,7 @@ static void TryDefaultInitialization(Sema &S,
// To default-initialize an object of type T means:
// - if T is an array type, each element is default-initialized;
QualType DestType = S.Context.getBaseElementType(Entity.getType());
-
+
// - if T is a (possibly cv-qualified) class type (Clause 9), the default
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
@@ -5043,11 +5043,11 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
// If we have a declaration reference, it had better be a local variable.
} else if (isa<DeclRefExpr>(e)) {
- // set isWeakAccess to true, to mean that there will be an implicit
+ // set isWeakAccess to true, to mean that there will be an implicit
// load which requires a cleanup.
if (e->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
isWeakAccess = true;
-
+
if (!isAddressOf) return IIK_nonlocal;
VarDecl *var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
@@ -5082,7 +5082,7 @@ static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
assert(src->isRValue());
bool isWeakAccess = false;
InvalidICRKind iik = isInvalidICRSource(S.Context, src, false, isWeakAccess);
- // If isWeakAccess to true, there will be an implicit
+ // If isWeakAccess to true, there will be an implicit
// load which requires a cleanup.
if (S.getLangOpts().ObjCAutoRefCount && isWeakAccess)
S.Cleanup.setExprNeedsCleanups(true);
@@ -5124,7 +5124,7 @@ static bool tryObjCWritebackConversion(Sema &S,
ArgPointee = ArgArrayType->getElementType();
ArgType = S.Context.getPointerType(ArgPointee);
}
-
+
// Handle write-back conversion.
QualType ConvertedArgType;
if (!S.isObjCWritebackConversion(ArgType, Entity.getType(),
@@ -5151,10 +5151,10 @@ static bool tryObjCWritebackConversion(Sema &S,
ICS.Standard.First = ICK_Lvalue_To_Rvalue;
ResultType = Initializer->getType().getNonLValueExprType(S.Context);
}
-
+
Sequence.AddConversionSequenceStep(ICS, ResultType);
}
-
+
Sequence.AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
return true;
}
@@ -5567,13 +5567,13 @@ void InitializationSequence::InitializeFrom(Sema &S,
if (ICS.isStandard() &&
ICS.Standard.Second == ICK_Writeback_Conversion) {
// Objective-C ARC writeback conversion.
-
+
// We should copy unless we're passing to an argument explicitly
// marked 'out'.
bool ShouldCopy = true;
if (ParmVarDecl *Param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
ShouldCopy = (Param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
-
+
// If there was an lvalue adjustment, add it as a separate conversion.
if (ICS.Standard.First == ICK_Array_To_Pointer ||
ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
@@ -5584,7 +5584,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
LvalueICS.Standard.First = ICS.Standard.First;
AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0));
}
-
+
AddPassByIndirectCopyRestoreStep(DestType, ShouldCopy);
} else if (ICS.isBad()) {
DeclAccessPair dap;
@@ -5635,9 +5635,9 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) {
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:
case InitializedEntity::EK_StmtExprResult: // FIXME: Not quite right.
return Sema::AA_Returning;
@@ -5743,7 +5743,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
case InitializedEntity::EK_LambdaCapture:
return Entity.getCaptureLoc();
-
+
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Member:
case InitializedEntity::EK_Parameter:
@@ -6065,9 +6065,9 @@ PerformConstructorInitialization(Sema &S,
ExprResult CurInit((Expr *)nullptr);
// C++ [over.match.copy]p1:
- // - When initializing a temporary to be bound to the first parameter
- // of a constructor that takes a reference to possibly cv-qualified
- // T as its first argument, called with a single argument in the
+ // - When initializing a temporary to be bound to the first parameter
+ // of a constructor that takes a reference to possibly cv-qualified
+ // T as its first argument, called with a single argument in the
// context of direct-initialization, explicit conversion functions
// are also considered.
bool AllowExplicitConv =
@@ -6322,12 +6322,14 @@ struct IndirectLocalPathEntry {
AddressOf,
VarInit,
LValToRVal,
+ LifetimeBoundCall,
} Kind;
Expr *E;
- Decl *D = nullptr;
+ const 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) {}
+ IndirectLocalPathEntry(EntryKind K, Expr *E, const Decl *D)
+ : Kind(K), E(E), D(D) {}
};
using IndirectLocalPath = llvm::SmallVectorImpl<IndirectLocalPathEntry>;
@@ -6361,6 +6363,68 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
bool RevisitSubinits);
+static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
+ Expr *Init, ReferenceKind RK,
+ LocalVisitor Visit);
+
+static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
+ const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
+ if (!TSI)
+ return false;
+ for (TypeLoc TL = TSI->getTypeLoc();
+ auto ATL = TL.getAsAdjusted<AttributedTypeLoc>();
+ TL = ATL.getModifiedLoc()) {
+ if (ATL.getAttrKind() == AttributedType::attr_lifetimebound)
+ return true;
+ }
+ return false;
+}
+
+static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
+ LocalVisitor Visit) {
+ const FunctionDecl *Callee;
+ ArrayRef<Expr*> Args;
+
+ if (auto *CE = dyn_cast<CallExpr>(Call)) {
+ Callee = CE->getDirectCallee();
+ Args = llvm::makeArrayRef(CE->getArgs(), CE->getNumArgs());
+ } else {
+ auto *CCE = cast<CXXConstructExpr>(Call);
+ Callee = CCE->getConstructor();
+ Args = llvm::makeArrayRef(CCE->getArgs(), CCE->getNumArgs());
+ }
+ if (!Callee)
+ return;
+
+ Expr *ObjectArg = nullptr;
+ if (isa<CXXOperatorCallExpr>(Call) && Callee->isCXXInstanceMember()) {
+ ObjectArg = Args[0];
+ Args = Args.slice(1);
+ } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
+ ObjectArg = MCE->getImplicitObjectArgument();
+ }
+
+ auto VisitLifetimeBoundArg = [&](const Decl *D, Expr *Arg) {
+ Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D});
+ if (Arg->isGLValue())
+ visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
+ Visit);
+ else
+ visitLocalsRetainedByInitializer(Path, Arg, Visit, true);
+ Path.pop_back();
+ };
+
+ if (ObjectArg && implicitObjectParamIsLifetimeBound(Callee))
+ VisitLifetimeBoundArg(Callee, ObjectArg);
+
+ for (unsigned I = 0,
+ N = std::min<unsigned>(Callee->getNumParams(), Args.size());
+ I != N; ++I) {
+ if (Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
+ VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
+ }
+}
+
/// Visit the locals that would be reachable through a reference bound to the
/// glvalue expression \c Init.
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
@@ -6420,6 +6484,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
true);
}
+ if (isa<CallExpr>(Init))
+ return visitLifetimeBoundArguments(Path, Init, Visit);
+
switch (Init->getStmtClass()) {
case Stmt::DeclRefExprClass: {
// If we find the name of a local non-reference parameter, we could have a
@@ -6483,21 +6550,90 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
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();
- }
+ Expr *Old;
+ do {
+ Old = Init;
- if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
- Init = EWC->getSubExpr();
+ // 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();
+ }
- // Dig out the expression which constructs the extended temporary.
- Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
+ 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 (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
+ Init = BTE->getSubExpr();
+
+ Init = Init->IgnoreParens();
+
+ // Step over value-preserving rvalue casts.
+ if (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() &&
+ !isVarOnPath(Path, VD)) {
+ 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_UserDefinedConversion:
+ case CK_ConstructorConversion:
+ 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;
+ }
+
+ Init = CE->getSubExpr();
+ }
+ } while (Old != Init);
// C++17 [dcl.init.list]p6:
// initializing an initializer_list object from the array extends the
@@ -6558,66 +6694,9 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
return;
}
- // 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;
- }
-
- Init = CE->getSubExpr();
- }
+ if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init))
+ return visitLifetimeBoundArguments(Path, Init, Visit);
- Init = Init->IgnoreParens();
switch (Init->getStmtClass()) {
case Stmt::UnaryOperatorClass: {
auto *UO = cast<UnaryOperator>(Init);
@@ -6697,6 +6776,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
switch (Path[I].Kind) {
case IndirectLocalPathEntry::AddressOf:
case IndirectLocalPathEntry::LValToRVal:
+ case IndirectLocalPathEntry::LifetimeBoundCall:
// These exist primarily to mark the path as not permitting or
// supporting lifetime extension.
break;
@@ -6767,8 +6847,9 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
return false;
Diag(DiagLoc, diag::warn_dangling_variable)
- << RK << !Entity.getParent() << ExtendingEntity->getDecl()
- << Init->isGLValue() << DiagRange;
+ << RK << !Entity.getParent()
+ << ExtendingEntity->getDecl()->isImplicit()
+ << ExtendingEntity->getDecl() << Init->isGLValue() << DiagRange;
}
break;
}
@@ -6875,6 +6956,10 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
// supporting lifetime extension.
break;
+ case IndirectLocalPathEntry::LifetimeBoundCall:
+ // FIXME: Consider adding a note for this.
+ break;
+
case IndirectLocalPathEntry::DefaultInit: {
auto *FD = cast<FieldDecl>(Elem.D);
Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer)
@@ -6885,7 +6970,8 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
case IndirectLocalPathEntry::VarInit:
const VarDecl *VD = cast<VarDecl>(Elem.D);
Diag(VD->getLocation(), diag::note_local_var_initializer)
- << VD->getType()->isReferenceType() << VD->getDeclName()
+ << VD->getType()->isReferenceType()
+ << VD->isImplicit() << VD->getDeclName()
<< nextPathEntryRange(Path, I + 1, L);
break;
}
@@ -7129,7 +7215,7 @@ InitializationSequence::Perform(Sema &S,
Args);
}
assert(Kind.getKind() == InitializationKind::IK_Copy ||
- Kind.isExplicitCast() ||
+ Kind.isExplicitCast() ||
Kind.getKind() == InitializationKind::IK_DirectList);
return ExprResult(Args[0]);
}
@@ -7831,7 +7917,7 @@ InitializationSequence::Perform(Sema &S,
// this has already been done when parsing the variable declaration.
if (!Init->isConstantInitializer(S.Context, false))
break;
-
+
if (!SourceType->isIntegerType() ||
32 != S.Context.getIntWidth(SourceType)) {
S.Diag(Kind.getLocation(), diag::err_sampler_initializer_not_integer)
@@ -7867,7 +7953,7 @@ InitializationSequence::Perform(Sema &S,
break;
}
case SK_OCLZeroEvent: {
- assert(Step->Type->isEventT() &&
+ assert(Step->Type->isEventT() &&
"Event initialization on non-event type.");
CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
@@ -8364,7 +8450,7 @@ bool InitializationSequence::Diagnose(Sema &S,
llvm_unreachable("Inconsistent overload resolution?");
break;
}
-
+
// If this is a defaulted or implicitly-declared function, then
// it was implicitly deleted. Make it clear that the deletion was
// implicit.