summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaInit.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2018-07-23 21:21:22 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2018-07-23 21:21:22 +0000
commitafe48f9d68e446829bed6ce72b319c915873809a (patch)
treecf4d1852819f96f709701e9e7c9b6088d77d74c5 /clang/lib/Sema/SemaInit.cpp
parentf9f50f634d4d6cae8d844b5a7b764e1159dce8e4 (diff)
downloadbcm5719-llvm-afe48f9d68e446829bed6ce72b319c915873809a.tar.gz
bcm5719-llvm-afe48f9d68e446829bed6ce72b319c915873809a.zip
Fold -Wreturn-stack-address into general initialization lifetime
checking. llvm-svn: 337743
Diffstat (limited to 'clang/lib/Sema/SemaInit.cpp')
-rw-r--r--clang/lib/Sema/SemaInit.cpp436
1 files changed, 318 insertions, 118 deletions
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index e457de4dcc7..5c891bebea8 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/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"
@@ -6348,18 +6349,28 @@ enum ReferenceKind {
RK_StdInitializerList,
};
-/// A temporary or local variable.
-using Local = llvm::PointerUnion<MaterializeTemporaryExpr*, ValueDecl*>;
+/// 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 {
+ 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>;
@@ -6370,16 +6381,24 @@ struct RevertToOldSizeRAII {
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;
}
-template <typename LocalVisitor>
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.
-template <typename LocalVisitor>
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
LocalVisitor Visit) {
@@ -6390,6 +6409,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
do {
Old = Init;
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
+ Init = EWC->getSubExpr();
+
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
// If this is just redundant braces around an initializer, step over it.
if (ILE->isTransparent())
@@ -6409,20 +6431,22 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
// Per the current approach for DR1299, look through array element access
// on array glvalues when performing lifetime extension.
if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init)) {
- auto *ICE = dyn_cast<ImplicitCastExpr>(ASE->getBase());
- if (!ICE || ICE->getCastKind() != CK_ArrayToPointerDecay)
- return;
- Init = ICE->getSubExpr();
+ 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});
+ Path.push_back(
+ {IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
Init = DIE->getExpr();
-
- if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
- Init = EWC->getSubExpr();
}
} while (Init != Old);
@@ -6432,22 +6456,64 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
true);
}
- // If we find the name of a local non-reference parameter, we could have a
- // lifetime problem.
- if (auto *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {
+ 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()) {
- // FIXME: Recurse to the initializer of a local reference.
- if (!VD->getType()->isReferenceType())
- Visit(Path, Local(VD), RK);
+ 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;
+ }
+
+ 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;
}
}
/// Visit the locals that would be reachable through an object initialized by
/// the prvalue expression \c Init.
-template <typename LocalVisitor>
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
bool RevisitSubinits) {
@@ -6456,13 +6522,13 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &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});
+ Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
Init = DIE->getExpr();
-
- if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
- Init = EWC->getSubExpr();
}
+ 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());
@@ -6528,15 +6594,119 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
return;
}
- // If the initializer is the address of a local, we could have a lifetime
- // problem.
- if (auto *Op = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) {
- if (Op->getOpcode() == UO_AddrOf) {
- Path.push_back({IndirectLocalPathEntry::AddressOf, Op});
- Init = Op->getSubExpr();
- return visitLocalsRetainedByReferenceBinding(Path, Init,
+ // 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();
+ }
+
+ 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) {
+ 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;
}
}
@@ -6563,58 +6733,20 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L,
ReferenceKind RK) -> bool {
- // If we found a path to a local variable or similar, check whether the
- // initialized object will outlive it.
- if (auto *VD = L.dyn_cast<ValueDecl*>()) {
- switch (LK) {
- case LK_FullExpression:
- llvm_unreachable("already handled this");
-
- case LK_Extended:
- break;
-
- case LK_MemInitializer: {
- // 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 (std::any_of(Path.begin(), Path.end(), [](IndirectLocalPathEntry E) {
- return E.Kind == IndirectLocalPathEntry::DefaultInit;
- }))
- break;
-
- if (auto *Member =
- ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
- bool AddressTaken =
- !Path.empty() &&
- Path.back().Kind == IndirectLocalPathEntry::AddressOf;
- Diag(Init->getExprLoc(),
- AddressTaken ? diag::warn_init_ptr_member_to_parameter_addr
- : diag::warn_bind_ref_member_to_parameter)
- << Member << VD << isa<ParmVarDecl>(VD) << Init->getSourceRange();
- Diag(Member->getLocation(),
- diag::note_ref_or_ptr_member_declared_here)
- << (unsigned)AddressTaken;
- }
- break;
- }
-
- case LK_New:
- break;
-
- case LK_Return:
- case LK_StmtExprResult:
- // FIXME: Move -Wreturn-stack-address checks here.
- return false;
- }
- return false;
- }
+ Expr *First = Path.empty() ? L : Path.front().E;
+ SourceLocation DiagLoc = First->getLocStart();
+ SourceRange DiagRange = First->getSourceRange();
- auto *MTE = L.get<MaterializeTemporaryExpr*>();
switch (LK) {
case LK_FullExpression:
llvm_unreachable("already handled this");
- case LK_Extended:
+ case LK_Extended: {
+ auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
+ if (!MTE)
+ // FIXME: Warn on this.
+ return false;
+
// Lifetime-extend the temporary.
if (Path.empty()) {
// Update the storage duration of the materialized temporary.
@@ -6632,70 +6764,138 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
// 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(MTE->getExprLoc(),
+ Diag(DiagLoc,
RK == RK_ReferenceBinding
? diag::warn_default_member_init_temporary_not_extended
- : diag::warn_default_member_init_init_list_not_extended);
+ : diag::warn_default_member_init_init_list_not_extended)
+ << DiagRange;
} else {
// FIXME: Warn on this.
+ return false;
}
break;
+ }
- case LK_MemInitializer:
- // 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(MTE->getExprLoc(), diag::err_bind_ref_member_to_temporary)
- << ExtendingDecl << Init->getSourceRange() << IsSubobjectMember
- << RK;
- // 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;
+ case LK_MemInitializer: {
+ if (auto *MTE = dyn_cast<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, diag::err_bind_ref_member_to_temporary)
+ << 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 {
- // 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. Either way, that can't happen.
- // FIXME: Move CheckForDanglingReferenceOrPointer checks here.
- llvm_unreachable(
- "temporary initializer for base class / delegating ctor");
+ // 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 (std::any_of(Path.begin(), Path.end(), [](IndirectLocalPathEntry E) {
+ return E.Kind == IndirectLocalPathEntry::DefaultInit;
+ }))
+ 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 (RK == RK_ReferenceBinding) {
- Diag(MTE->getExprLoc(), diag::warn_new_dangling_reference);
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
+ Diag(DiagLoc, RK == RK_ReferenceBinding
+ ? diag::warn_new_dangling_reference
+ : diag::warn_new_dangling_initializer_list)
+ << (ExtendingEntity != &Entity) << DiagRange;
} else {
- Diag(MTE->getExprLoc(), diag::warn_new_dangling_initializer_list)
- << (ExtendingEntity != &Entity);
+ // We can't determine if the allocation outlives the local declaration.
+ return false;
}
break;
case LK_Return:
case LK_StmtExprResult:
- // FIXME: Move -Wreturn-stack-address checks here.
- return false;
+ 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;
}
- // FIXME: Model these as CodeSynthesisContexts to fix the note emission
- // order.
- for (auto Elem : llvm::reverse(Path)) {
+ for (unsigned I = 0; I != Path.size(); ++I) {
+ auto Elem = Path[I];
+
+ // Highlight the range of the next step within this path element.
+ SourceRange Range;
+ if (I < Path.size() - 1)
+ Range = Path[I + 1].E->getSourceRange();
+ else
+ Range = L->getSourceRange();
+
switch (Elem.Kind) {
- case IndirectLocalPathEntry::DefaultInit:
- Diag(Elem.E->getExprLoc(), diag::note_in_default_member_initalizer_here)
- << cast<CXXDefaultInitExpr>(Elem.E)->getField();
+ case IndirectLocalPathEntry::AddressOf:
+ case IndirectLocalPathEntry::LValToRVal:
+ // These exist primarily to mark the path as not permitting lifetime
+ // extension.
break;
- case IndirectLocalPathEntry::AddressOf:
+ case IndirectLocalPathEntry::DefaultInit: {
+ auto *FD = cast<FieldDecl>(Elem.D);
+ Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer)
+ << FD << Range;
+ break;
+ }
+
+ case IndirectLocalPathEntry::VarInit:
+ const VarDecl *VD = cast<VarDecl>(Elem.D);
+ Diag(VD->getLocation(), diag::note_local_var_initializer)
+ << VD->getType()->isReferenceType() << VD->getDeclName() << Range;
break;
}
}
OpenPOWER on IntegriCloud