forked from OSchip/llvm-project
Extend the self-reference warning to catch when a constructor references itself upon initialization, such as using itself within its own copy constructor.
struct S {}; S s(s); llvm-svn: 138969
This commit is contained in:
parent
a3ba6d3b80
commit
a04ad1a1b9
|
@ -1035,6 +1035,7 @@ public:
|
|||
bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg,
|
||||
SourceLocation EqualLoc);
|
||||
|
||||
void CheckSelfReference(Decl *OrigDecl, Expr *E);
|
||||
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit,
|
||||
bool TypeMayContainAuto);
|
||||
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
|
||||
|
|
|
@ -5407,41 +5407,88 @@ namespace {
|
|||
: public EvaluatedExprVisitor<SelfReferenceChecker> {
|
||||
Sema &S;
|
||||
Decl *OrigDecl;
|
||||
bool isRecordType;
|
||||
bool isPODType;
|
||||
|
||||
public:
|
||||
typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited;
|
||||
|
||||
SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context),
|
||||
S(S), OrigDecl(OrigDecl) { }
|
||||
S(S), OrigDecl(OrigDecl) {
|
||||
isPODType = false;
|
||||
isRecordType = false;
|
||||
if (ValueDecl *VD = dyn_cast<ValueDecl>(OrigDecl)) {
|
||||
isPODType = VD->getType().isPODType(S.Context);
|
||||
isRecordType = VD->getType()->isRecordType();
|
||||
}
|
||||
}
|
||||
|
||||
void VisitExpr(Expr *E) {
|
||||
if (isa<ObjCMessageExpr>(*E)) return;
|
||||
if (isRecordType) {
|
||||
Expr *expr = E;
|
||||
if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
|
||||
ValueDecl *VD = ME->getMemberDecl();
|
||||
if (isa<EnumConstantDecl>(VD) || isa<VarDecl>(VD)) return;
|
||||
expr = ME->getBase();
|
||||
}
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(expr)) {
|
||||
HandleDeclRefExpr(DRE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Inherited::VisitExpr(E);
|
||||
}
|
||||
|
||||
void VisitMemberExpr(MemberExpr *E) {
|
||||
if (isa<FieldDecl>(E->getMemberDecl()))
|
||||
if (DeclRefExpr *DRE
|
||||
= dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) {
|
||||
HandleDeclRefExpr(DRE);
|
||||
return;
|
||||
}
|
||||
Inherited::VisitMemberExpr(E);
|
||||
}
|
||||
|
||||
void VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
||||
CheckForSelfReference(E);
|
||||
if ((!isRecordType &&E->getCastKind() == CK_LValueToRValue) ||
|
||||
(isRecordType && E->getCastKind() == CK_NoOp)) {
|
||||
Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
|
||||
if (MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr))
|
||||
SubExpr = ME->getBase()->IgnoreParenImpCasts();
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) {
|
||||
HandleDeclRefExpr(DRE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Inherited::VisitImplicitCastExpr(E);
|
||||
}
|
||||
|
||||
void CheckForSelfReference(ImplicitCastExpr *E) {
|
||||
if (E->getCastKind() != CK_LValueToRValue) return;
|
||||
Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
|
||||
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr);
|
||||
if (!DRE) return;
|
||||
Decl* ReferenceDecl = DRE->getDecl();
|
||||
void VisitUnaryOperator(UnaryOperator *E) {
|
||||
// For POD record types, addresses of its own members are well-defined.
|
||||
if (isRecordType && isPODType) return;
|
||||
Inherited::VisitUnaryOperator(E);
|
||||
}
|
||||
|
||||
void HandleDeclRefExpr(DeclRefExpr *DRE) {
|
||||
Decl* ReferenceDecl = DRE->getDecl();
|
||||
if (OrigDecl != ReferenceDecl) return;
|
||||
LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
|
||||
Sema::NotForRedeclaration);
|
||||
S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr,
|
||||
S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,
|
||||
S.PDiag(diag::warn_uninit_self_reference_in_init)
|
||||
<< Result.getLookupName()
|
||||
<< Result.getLookupName()
|
||||
<< OrigDecl->getLocation()
|
||||
<< SubExpr->getSourceRange());
|
||||
<< DRE->getSourceRange());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// CheckSelfReference - Warns if OrigDecl is used in expression E.
|
||||
void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) {
|
||||
SelfReferenceChecker(*this, OrigDecl).VisitExpr(E);
|
||||
}
|
||||
|
||||
/// AddInitializerToDecl - Adds the initializer Init to the
|
||||
/// declaration dcl. If DirectInit is true, this is C++ direct
|
||||
/// initialization rather than copy initialization.
|
||||
|
@ -5457,10 +5504,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
// Variables declared within a function/method body are handled
|
||||
// by a dataflow analysis.
|
||||
if (!vd->hasLocalStorage() && !vd->isStaticLocal())
|
||||
SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
|
||||
CheckSelfReference(RealDecl, Init);
|
||||
}
|
||||
else {
|
||||
SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
|
||||
CheckSelfReference(RealDecl, Init);
|
||||
}
|
||||
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
|
||||
|
|
|
@ -3078,6 +3078,14 @@ static void TryConstructorInitialization(Sema &S,
|
|||
Expr **Args, unsigned NumArgs,
|
||||
QualType DestType,
|
||||
InitializationSequence &Sequence) {
|
||||
// Check constructor arguments for self reference.
|
||||
if (DeclaratorDecl *DD = Entity.getDecl())
|
||||
// Parameters arguments are occassionially constructed with itself,
|
||||
// for instance, in recursive functions. Skip them.
|
||||
if (!isa<ParmVarDecl>(DD))
|
||||
for (unsigned i = 0; i < NumArgs; ++i)
|
||||
S.CheckSelfReference(DD, Args[i]);
|
||||
|
||||
// Build the candidate set directly in the initialization sequence
|
||||
// structure, so that it will persist if we fail.
|
||||
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
|
||||
|
|
|
@ -24,6 +24,78 @@ int i = boo(i);
|
|||
int j = far(j);
|
||||
int k = __alignof__(k);
|
||||
|
||||
|
||||
// Test self-references with record types.
|
||||
class A {
|
||||
// Non-POD class.
|
||||
public:
|
||||
enum count { ONE, TWO, THREE };
|
||||
int num;
|
||||
static int count;
|
||||
int get() const { return num; }
|
||||
void set(int x) { num = x; }
|
||||
static int zero() { return 0; }
|
||||
|
||||
A() {}
|
||||
A(A const &a) {}
|
||||
A(int x) {}
|
||||
A(int *x) {}
|
||||
A(A *a) {}
|
||||
};
|
||||
|
||||
A getA() { return A(); }
|
||||
A getA(int x) { return A(); }
|
||||
A getA(A* a) { return A(); }
|
||||
|
||||
void setupA() {
|
||||
A a1;
|
||||
a1.set(a1.get());
|
||||
A a2(a1.get());
|
||||
A a3(a1);
|
||||
A a4(&a4);
|
||||
A a5(a5.zero());
|
||||
A a6(a6.ONE);
|
||||
A a7 = getA();
|
||||
A a8 = getA(a8.TWO);
|
||||
A a9 = getA(&a9);
|
||||
A a10(a10.count);
|
||||
|
||||
A a11(a11); // expected-warning {{variable 'a11' is uninitialized when used within its own initialization}}
|
||||
A a12(a12.get()); // expected-warning {{variable 'a12' is uninitialized when used within its own initialization}}
|
||||
A a13(a13.num); // expected-warning {{variable 'a13' is uninitialized when used within its own initialization}}
|
||||
A a14 = A(a14); // expected-warning {{variable 'a14' is uninitialized when used within its own initialization}}
|
||||
A a15 = getA(a15.num); // expected-warning {{variable 'a15' is uninitialized when used within its own initialization}}
|
||||
A a16(&a16.num); // expected-warning {{variable 'a16' is uninitialized when used within its own initialization}}
|
||||
}
|
||||
|
||||
struct B {
|
||||
// POD struct.
|
||||
int x;
|
||||
int *y;
|
||||
};
|
||||
|
||||
B getB() { return B(); };
|
||||
B getB(int x) { return B(); };
|
||||
B getB(int *x) { return B(); };
|
||||
B getB(B *b) { return B(); };
|
||||
|
||||
void setupB() {
|
||||
B b1;
|
||||
B b2(b1);
|
||||
B b3 = { 5, &b3.x };
|
||||
B b4 = getB();
|
||||
B b5 = getB(&b5);
|
||||
B b6 = getB(&b6.x);
|
||||
|
||||
// Silence unused warning
|
||||
(void) b2;
|
||||
(void) b4;
|
||||
|
||||
B b7(b7); // expected-warning {{variable 'b7' is uninitialized when used within its own initialization}}
|
||||
B b8 = getB(b8.x); // expected-warning {{variable 'b8' is uninitialized when used within its own initialization}}
|
||||
B b9 = getB(b9.y); // expected-warning {{variable 'b9' is uninitialized when used within its own initialization}}
|
||||
}
|
||||
|
||||
// Also test similar constructs in a field's initializer.
|
||||
struct S {
|
||||
int x;
|
||||
|
|
Loading…
Reference in New Issue