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,
|
bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg,
|
||||||
SourceLocation EqualLoc);
|
SourceLocation EqualLoc);
|
||||||
|
|
||||||
|
void CheckSelfReference(Decl *OrigDecl, Expr *E);
|
||||||
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit,
|
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit,
|
||||||
bool TypeMayContainAuto);
|
bool TypeMayContainAuto);
|
||||||
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
|
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
|
||||||
|
|
|
@ -5407,41 +5407,88 @@ namespace {
|
||||||
: public EvaluatedExprVisitor<SelfReferenceChecker> {
|
: public EvaluatedExprVisitor<SelfReferenceChecker> {
|
||||||
Sema &S;
|
Sema &S;
|
||||||
Decl *OrigDecl;
|
Decl *OrigDecl;
|
||||||
|
bool isRecordType;
|
||||||
|
bool isPODType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited;
|
typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited;
|
||||||
|
|
||||||
SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context),
|
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) {
|
void VisitExpr(Expr *E) {
|
||||||
if (isa<ObjCMessageExpr>(*E)) return;
|
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);
|
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) {
|
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);
|
Inherited::VisitImplicitCastExpr(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckForSelfReference(ImplicitCastExpr *E) {
|
void VisitUnaryOperator(UnaryOperator *E) {
|
||||||
if (E->getCastKind() != CK_LValueToRValue) return;
|
// For POD record types, addresses of its own members are well-defined.
|
||||||
Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
|
if (isRecordType && isPODType) return;
|
||||||
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr);
|
Inherited::VisitUnaryOperator(E);
|
||||||
if (!DRE) return;
|
}
|
||||||
|
|
||||||
|
void HandleDeclRefExpr(DeclRefExpr *DRE) {
|
||||||
Decl* ReferenceDecl = DRE->getDecl();
|
Decl* ReferenceDecl = DRE->getDecl();
|
||||||
if (OrigDecl != ReferenceDecl) return;
|
if (OrigDecl != ReferenceDecl) return;
|
||||||
LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
|
LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
|
||||||
Sema::NotForRedeclaration);
|
Sema::NotForRedeclaration);
|
||||||
S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr,
|
S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,
|
||||||
S.PDiag(diag::warn_uninit_self_reference_in_init)
|
S.PDiag(diag::warn_uninit_self_reference_in_init)
|
||||||
<< Result.getLookupName()
|
<< Result.getLookupName()
|
||||||
<< OrigDecl->getLocation()
|
<< 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
|
/// AddInitializerToDecl - Adds the initializer Init to the
|
||||||
/// declaration dcl. If DirectInit is true, this is C++ direct
|
/// declaration dcl. If DirectInit is true, this is C++ direct
|
||||||
/// initialization rather than copy initialization.
|
/// 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
|
// Variables declared within a function/method body are handled
|
||||||
// by a dataflow analysis.
|
// by a dataflow analysis.
|
||||||
if (!vd->hasLocalStorage() && !vd->isStaticLocal())
|
if (!vd->hasLocalStorage() && !vd->isStaticLocal())
|
||||||
SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
|
CheckSelfReference(RealDecl, Init);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
|
CheckSelfReference(RealDecl, Init);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
|
||||||
|
|
|
@ -3078,6 +3078,14 @@ static void TryConstructorInitialization(Sema &S,
|
||||||
Expr **Args, unsigned NumArgs,
|
Expr **Args, unsigned NumArgs,
|
||||||
QualType DestType,
|
QualType DestType,
|
||||||
InitializationSequence &Sequence) {
|
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
|
// Build the candidate set directly in the initialization sequence
|
||||||
// structure, so that it will persist if we fail.
|
// structure, so that it will persist if we fail.
|
||||||
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
|
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
|
||||||
|
|
|
@ -24,6 +24,78 @@ int i = boo(i);
|
||||||
int j = far(j);
|
int j = far(j);
|
||||||
int k = __alignof__(k);
|
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.
|
// Also test similar constructs in a field's initializer.
|
||||||
struct S {
|
struct S {
|
||||||
int x;
|
int x;
|
||||||
|
|
Loading…
Reference in New Issue