Skip to content

Commit 3630c39

Browse files
committedNov 21, 2014
Extend -Wuninitialized to warn when accessing uninitialized base classes in a
constructor. llvm-svn: 222503
1 parent e3d126c commit 3630c39

File tree

3 files changed

+83
-12
lines changed

3 files changed

+83
-12
lines changed
 

‎clang/include/clang/Basic/DiagnosticSemaKinds.td

+3
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,9 @@ def note_uninit_reference_member : Note<
14961496
"uninitialized reference member is here">;
14971497
def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">,
14981498
InGroup<Uninitialized>;
1499+
def warn_base_class_is_uninit : Warning<
1500+
"base class %0 is uninitialized when used here to access %q1">,
1501+
InGroup<Uninitialized>;
14991502
def warn_reference_field_is_uninit : Warning<
15001503
"reference %0 is not yet bound to a value when used here">,
15011504
InGroup<Uninitialized>;

‎clang/lib/Sema/SemaDeclCXX.cpp

+41-12
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,9 @@ namespace {
22372237
// List of Decls to generate a warning on. Also remove Decls that become
22382238
// initialized.
22392239
llvm::SmallPtrSetImpl<ValueDecl*> &Decls;
2240+
// List of base classes of the record. Classes are removed after their
2241+
// initializers.
2242+
llvm::SmallPtrSetImpl<QualType> &BaseClasses;
22402243
// Vector of decls to be removed from the Decl set prior to visiting the
22412244
// nodes. These Decls may have been initialized in the prior initializer.
22422245
llvm::SmallVector<ValueDecl*, 4> DeclsToRemove;
@@ -2252,9 +2255,10 @@ namespace {
22522255
public:
22532256
typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
22542257
UninitializedFieldVisitor(Sema &S,
2255-
llvm::SmallPtrSetImpl<ValueDecl*> &Decls)
2256-
: Inherited(S.Context), S(S), Decls(Decls), Constructor(nullptr),
2257-
InitList(false), InitListFieldDecl(nullptr) {}
2258+
llvm::SmallPtrSetImpl<ValueDecl*> &Decls,
2259+
llvm::SmallPtrSetImpl<QualType> &BaseClasses)
2260+
: Inherited(S.Context), S(S), Decls(Decls), BaseClasses(BaseClasses),
2261+
Constructor(nullptr), InitList(false), InitListFieldDecl(nullptr) {}
22582262

22592263
// Returns true if the use of ME is not an uninitialized use.
22602264
bool IsInitListMemberExprInitialized(MemberExpr *ME,
@@ -2309,7 +2313,8 @@ namespace {
23092313
bool AllPODFields = FieldME->getType().isPODType(S.Context);
23102314

23112315
Expr *Base = ME;
2312-
while (MemberExpr *SubME = dyn_cast<MemberExpr>(Base)) {
2316+
while (MemberExpr *SubME =
2317+
dyn_cast<MemberExpr>(Base->IgnoreParenImpCasts())) {
23132318

23142319
if (isa<VarDecl>(SubME->getMemberDecl()))
23152320
return;
@@ -2321,17 +2326,32 @@ namespace {
23212326
if (!FieldME->getType().isPODType(S.Context))
23222327
AllPODFields = false;
23232328

2324-
Base = SubME->getBase()->IgnoreParenImpCasts();
2329+
Base = SubME->getBase();
23252330
}
23262331

2327-
if (!isa<CXXThisExpr>(Base))
2332+
if (!isa<CXXThisExpr>(Base->IgnoreParenImpCasts()))
23282333
return;
23292334

23302335
if (AddressOf && AllPODFields)
23312336
return;
23322337

23332338
ValueDecl* FoundVD = FieldME->getMemberDecl();
23342339

2340+
if (ImplicitCastExpr *BaseCast = dyn_cast<ImplicitCastExpr>(Base)) {
2341+
while (isa<ImplicitCastExpr>(BaseCast->getSubExpr())) {
2342+
BaseCast = cast<ImplicitCastExpr>(BaseCast->getSubExpr());
2343+
}
2344+
2345+
if (BaseCast->getCastKind() == CK_UncheckedDerivedToBase) {
2346+
QualType T = BaseCast->getType();
2347+
if (T->isPointerType() &&
2348+
BaseClasses.count(T->getPointeeType())) {
2349+
S.Diag(FieldME->getExprLoc(), diag::warn_base_class_is_uninit)
2350+
<< T->getPointeeType() << FoundVD;
2351+
}
2352+
}
2353+
}
2354+
23352355
if (!Decls.count(FoundVD))
23362356
return;
23372357

@@ -2420,7 +2440,7 @@ namespace {
24202440
}
24212441

24222442
void CheckInitializer(Expr *E, const CXXConstructorDecl *FieldConstructor,
2423-
FieldDecl *Field) {
2443+
FieldDecl *Field, const Type *BaseClass) {
24242444
// Remove Decls that may have been initialized in the previous
24252445
// initializer.
24262446
for (ValueDecl* VD : DeclsToRemove)
@@ -2442,6 +2462,8 @@ namespace {
24422462

24432463
if (Field)
24442464
Decls.erase(Field);
2465+
if (BaseClass)
2466+
BaseClasses.erase(BaseClass->getCanonicalTypeInternal());
24452467
}
24462468

24472469
void VisitMemberExpr(MemberExpr *ME) {
@@ -2578,14 +2600,19 @@ namespace {
25782600
}
25792601
}
25802602

2581-
if (UninitializedFields.empty())
2603+
llvm::SmallPtrSet<QualType, 4> UninitializedBaseClasses;
2604+
for (auto I : RD->bases())
2605+
UninitializedBaseClasses.insert(I.getType().getCanonicalType());
2606+
2607+
if (UninitializedFields.empty() && UninitializedBaseClasses.empty())
25822608
return;
25832609

25842610
UninitializedFieldVisitor UninitializedChecker(SemaRef,
2585-
UninitializedFields);
2611+
UninitializedFields,
2612+
UninitializedBaseClasses);
25862613

25872614
for (const auto *FieldInit : Constructor->inits()) {
2588-
if (UninitializedFields.empty())
2615+
if (UninitializedFields.empty() && UninitializedBaseClasses.empty())
25892616
break;
25902617

25912618
Expr *InitExpr = FieldInit->getInit();
@@ -2599,10 +2626,12 @@ namespace {
25992626
continue;
26002627
// In class initializers will point to the constructor.
26012628
UninitializedChecker.CheckInitializer(InitExpr, Constructor,
2602-
FieldInit->getAnyMember());
2629+
FieldInit->getAnyMember(),
2630+
FieldInit->getBaseClass());
26032631
} else {
26042632
UninitializedChecker.CheckInitializer(InitExpr, nullptr,
2605-
FieldInit->getAnyMember());
2633+
FieldInit->getAnyMember(),
2634+
FieldInit->getBaseClass());
26062635
}
26072636
}
26082637
}

‎clang/test/SemaCXX/uninitialized.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -1302,3 +1302,42 @@ C<int> c;
13021302
// expected-note@-1 {{in instantiation of member function 'template_class::C<int>::C' requested here}}
13031303

13041304
}
1305+
1306+
namespace base_class_access {
1307+
struct A {
1308+
A();
1309+
A(int);
1310+
1311+
int i;
1312+
int foo();
1313+
1314+
static int bar();
1315+
};
1316+
1317+
struct B : public A {
1318+
B(int (*)[1]) : A() {}
1319+
B(int (*)[2]) : A(bar()) {}
1320+
1321+
B(int (*)[3]) : A(i) {}
1322+
// expected-warning@-1 {{base class 'base_class_access::A' is uninitialized when used here to access 'base_class_access::A::i'}}
1323+
1324+
B(int (*)[4]) : A(foo()) {}
1325+
// expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}}
1326+
};
1327+
1328+
struct C {
1329+
C(int) {}
1330+
};
1331+
1332+
struct D : public C, public A {
1333+
D(int (*)[1]) : C(0) {}
1334+
D(int (*)[2]) : C(bar()) {}
1335+
1336+
D(int (*)[3]) : C(i) {}
1337+
// expected-warning@-1 {{base class 'base_class_access::A' is uninitialized when used here to access 'base_class_access::A::i'}}
1338+
1339+
D(int (*)[4]) : C(foo()) {}
1340+
// expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}}
1341+
};
1342+
1343+
}

0 commit comments

Comments
 (0)
Please sign in to comment.