forked from OSchip/llvm-project
Move detection of reference members binding to temporaries from building of
CXXCtorInitializers to the point where we perform the questionable lifetime extension. This exposed a selection of false negatives in the warning. llvm-svn: 183869
This commit is contained in:
parent
0c24b20d33
commit
e3b28bc363
|
@ -5947,10 +5947,12 @@ def warn_init_ptr_member_to_parameter_addr : Warning<
|
|||
"initializing pointer member %0 with the stack address of parameter %1">,
|
||||
InGroup<DanglingField>;
|
||||
def warn_bind_ref_member_to_temporary : Warning<
|
||||
"binding reference member %0 to a temporary value">,
|
||||
"binding reference %select{|subobject of }1member %0 to a temporary value">,
|
||||
InGroup<DanglingField>;
|
||||
def note_ref_or_ptr_member_declared_here : Note<
|
||||
"%select{reference|pointer}0 member declared here">;
|
||||
def note_ref_subobject_of_member_declared_here : Note<
|
||||
"member with reference subobject declared here">;
|
||||
|
||||
// For non-floating point, expressions of the form x == x or x != x
|
||||
// should result in a warning, since these always evaluate to a constant.
|
||||
|
|
|
@ -2479,15 +2479,7 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,
|
|||
}
|
||||
}
|
||||
|
||||
if (isa<MaterializeTemporaryExpr>(Init->IgnoreParens())) {
|
||||
// Taking the address of a temporary will be diagnosed as a hard error.
|
||||
if (IsPointer)
|
||||
return;
|
||||
|
||||
S.Diag(Init->getExprLoc(), diag::warn_bind_ref_member_to_temporary)
|
||||
<< Member << Init->getSourceRange();
|
||||
} else if (const DeclRefExpr *DRE
|
||||
= dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {
|
||||
// We only warn when referring to a non-reference parameter declaration.
|
||||
const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl());
|
||||
if (!Parameter || Parameter->getType()->isReferenceType())
|
||||
|
|
|
@ -2461,6 +2461,7 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
|
|||
{
|
||||
InitializedEntity Result;
|
||||
Result.Kind = EK_Base;
|
||||
Result.Parent = 0;
|
||||
Result.Base = reinterpret_cast<uintptr_t>(Base);
|
||||
if (IsInheritedVirtualBase)
|
||||
Result.Base |= 0x01;
|
||||
|
@ -2553,6 +2554,7 @@ bool InitializedEntity::allowsNRVO() const {
|
|||
}
|
||||
|
||||
unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
|
||||
assert(getParent() != this);
|
||||
unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0;
|
||||
for (unsigned I = 0; I != Depth; ++I)
|
||||
OS << "`-";
|
||||
|
@ -5566,9 +5568,33 @@ InitializationSequence::Perform(Sema &S,
|
|||
// entity's lifetime.
|
||||
const ValueDecl *ExtendingDecl =
|
||||
getDeclForTemporaryLifetimeExtension(Entity);
|
||||
if (ExtendingDecl)
|
||||
if (ExtendingDecl) {
|
||||
performLifetimeExtension(CurInit.get(), ExtendingDecl);
|
||||
|
||||
// Warn if a field lifetime-extends a temporary.
|
||||
if (isa<FieldDecl>(ExtendingDecl)) {
|
||||
bool IsSubobjectMember = false;
|
||||
for (const InitializedEntity *Ent = Entity.getParent(); Ent;
|
||||
Ent = Ent->getParent()) {
|
||||
if (Ent->getKind() != InitializedEntity::EK_Base) {
|
||||
IsSubobjectMember = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
S.Diag(CurInit.get()->getExprLoc(),
|
||||
diag::warn_bind_ref_member_to_temporary)
|
||||
<< ExtendingDecl << CurInit.get()->getSourceRange()
|
||||
<< IsSubobjectMember;
|
||||
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)
|
||||
<< /*IsPointer*/false;
|
||||
}
|
||||
}
|
||||
|
||||
// Materialize the temporary into memory.
|
||||
MaterializeTemporaryExpr *MTE = new (S.Context) MaterializeTemporaryExpr(
|
||||
Entity.getType().getNonReferenceType(), CurInit.get(),
|
||||
|
|
|
@ -116,6 +116,7 @@ HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy c
|
|||
// -- a non-static data member of rvalue reference type
|
||||
struct RValue {
|
||||
int && ri = 1; // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
|
||||
// expected-warning@-1{{binding reference member 'ri' to a temporary}} expected-note@-1 {{here}}
|
||||
};
|
||||
RValue RVa;
|
||||
RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}}
|
||||
|
|
|
@ -108,7 +108,7 @@ HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy c
|
|||
// The restriction on rvalue reference members applies to only the copy
|
||||
// constructor.
|
||||
struct RValue {
|
||||
int &&ri = 1;
|
||||
int &&ri = 1; // expected-warning {{binding reference member 'ri' to a temporary}} expected-note {{here}}
|
||||
RValue(RValue&&);
|
||||
};
|
||||
RValue::RValue(RValue&&) = default;
|
||||
|
|
|
@ -43,7 +43,7 @@ class NotDeleted2a { int &a = n; };
|
|||
NotDeleted2a nd2a;
|
||||
class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
|
||||
NotDeleted2b nd2b;
|
||||
class NotDeleted2c { int &&a = 0; };
|
||||
class NotDeleted2c { int &&a = 0; }; // expected-warning {{binding reference member 'a' to a temporary}} expected-note {{here}}
|
||||
NotDeleted2c nd2c;
|
||||
|
||||
// - any non-variant non-static data member of const qualified type (or array
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
// RUN: %clang_cc1 -verify %s -std=c++11
|
||||
// expected-no-diagnostics
|
||||
|
||||
template<const int I> struct S {
|
||||
decltype(I) n;
|
||||
int &&r = I;
|
||||
int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
|
||||
};
|
||||
S<5> s;
|
||||
S<5> s; // expected-note {{instantiation}}
|
||||
|
||||
template<typename T, T v> struct U {
|
||||
decltype(v) n;
|
||||
int &&r = v;
|
||||
int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
|
||||
};
|
||||
U<const int, 6> u;
|
||||
U<const int, 6> u; // expected-note {{instantiation}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Wdangling-field -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wdangling-field -verify -std=c++11 %s
|
||||
|
||||
struct X {
|
||||
X(int);
|
||||
|
@ -35,3 +35,17 @@ template <typename T> struct S4 {
|
|||
|
||||
template struct S4<int>; // no warning from this instantiation
|
||||
template struct S4<int&>; // expected-note {{in instantiation}}
|
||||
|
||||
struct S5 {
|
||||
const X &x; // expected-note {{here}}
|
||||
};
|
||||
S5 s5 = { 0 }; // ok, lifetime-extended
|
||||
|
||||
struct S6 {
|
||||
S5 s5; // expected-note {{here}}
|
||||
S6() : s5 { 0 } {} // expected-warning {{binding reference subobject of member 's5' to a temporary}}
|
||||
};
|
||||
|
||||
struct S7 : S5 {
|
||||
S7() : S5 { 0 } {} // expected-warning {{binding reference member 'x' to a temporary}}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue