CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
bool AnyErrors) {
- if (Constructor->isDependentContext()) {
+ if (Constructor->getDeclContext()->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
if (NumInitializers > 0) {
static void
DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
const CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **MemInits,
- unsigned NumMemInits) {
- if (Constructor->isDependentContext())
+ CXXBaseOrMemberInitializer **Inits,
+ unsigned NumInits) {
+ if (Constructor->getDeclContext()->isDependentContext())
return;
- if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
- Diagnostic::Ignored &&
- SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
- Diagnostic::Ignored)
+ if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order)
+ == Diagnostic::Ignored)
return;
- // Also issue warning if order of ctor-initializer list does not match order
- // of 1) base class declarations and 2) order of non-static data members.
- llvm::SmallVector<const void*, 32> AllBaseOrMembers;
+ // Build the list of bases and members in the order that they'll
+ // actually be initialized. The explicit initializers should be in
+ // this same order but may be missing things.
+ llvm::SmallVector<const void*, 32> IdealInitKeys;
const CXXRecordDecl *ClassDecl = Constructor->getParent();
- // Push virtual bases before others.
+ // 1. Virtual bases.
for (CXXRecordDecl::base_class_const_iterator VBase =
ClassDecl->vbases_begin(),
E = ClassDecl->vbases_end(); VBase != E; ++VBase)
- AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
- VBase->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType()));
+ // 2. Non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- // Virtuals are alread in the virtual base list and are constructed
- // first.
if (Base->isVirtual())
continue;
- AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
- Base->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType()));
}
+ // 3. Direct fields.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field)
- AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field));
+ IdealInitKeys.push_back(GetKeyForTopLevelField(*Field));
- int Last = AllBaseOrMembers.size();
- int curIndex = 0;
- CXXBaseOrMemberInitializer *PrevMember = 0;
- for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member = MemInits[i];
- void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true);
+ unsigned NumIdealInits = IdealInitKeys.size();
+ unsigned IdealIndex = 0;
- for (; curIndex < Last; curIndex++)
- if (MemberInCtorList == AllBaseOrMembers[curIndex])
+ CXXBaseOrMemberInitializer *PrevInit = 0;
+ for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ CXXBaseOrMemberInitializer *Init = Inits[InitIndex];
+ void *InitKey = GetKeyForMember(SemaRef.Context, Init, true);
+
+ // Scan forward to try to find this initializer in the idealized
+ // initializers list.
+ for (; IdealIndex != NumIdealInits; ++IdealIndex)
+ if (InitKey == IdealInitKeys[IdealIndex])
break;
- if (curIndex == Last) {
- assert(PrevMember && "Member not in member list?!");
- // Initializer as specified in ctor-initializer list is out of order.
- // Issue a warning diagnostic.
- if (PrevMember->isBaseInitializer()) {
- // Diagnostics is for an initialized base class.
- Type *BaseClass = PrevMember->getBaseClass();
- SemaRef.Diag(PrevMember->getSourceLocation(),
- diag::warn_base_initialized)
- << QualType(BaseClass, 0);
- } else {
- FieldDecl *Field = PrevMember->getMember();
- SemaRef.Diag(PrevMember->getSourceLocation(),
- diag::warn_field_initialized)
- << Field->getNameAsString();
- }
- // Also the note!
- if (FieldDecl *Field = Member->getMember())
- SemaRef.Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 0
- << Field->getNameAsString();
- else {
- Type *BaseClass = Member->getBaseClass();
- SemaRef.Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 1
- << QualType(BaseClass, 0);
- }
- for (curIndex = 0; curIndex < Last; curIndex++)
- if (MemberInCtorList == AllBaseOrMembers[curIndex])
+
+ // If we didn't find this initializer, it must be because we
+ // scanned past it on a previous iteration. That can only
+ // happen if we're out of order; emit a warning.
+ if (IdealIndex == NumIdealInits) {
+ assert(PrevInit && "initializer not found in initializer list");
+
+ Sema::SemaDiagnosticBuilder D =
+ SemaRef.Diag(PrevInit->getSourceLocation(),
+ diag::warn_initializer_out_of_order);
+
+ if (PrevInit->isMemberInitializer())
+ D << 0 << PrevInit->getMember()->getDeclName();
+ else
+ D << 1 << PrevInit->getBaseClassInfo()->getType();
+
+ if (Init->isMemberInitializer())
+ D << 0 << Init->getMember()->getDeclName();
+ else
+ D << 1 << Init->getBaseClassInfo()->getType();
+
+ // Move back to the initializer's location in the ideal list.
+ for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex)
+ if (InitKey == IdealInitKeys[IdealIndex])
break;
+
+ assert(IdealIndex != NumIdealInits &&
+ "initializer not found in initializer list");
}
- PrevMember = Member;
+
+ PrevInit = Init;
}
}
class complex : public BB, BB1 {
public:
- complex() : s2(1), // expected-warning {{member 's2' will be initialized after}}
- s1(1) , // expected-note {{field s1}}
- s3(3), // expected-warning {{member 's3' will be initialized after}}
- BB1(), // expected-note {{base 'BB1'}} \
- // expected-warning {{base class 'BB1' will be initialized after}}
- BB() {} // expected-note {{base 'BB'}}
+ complex()
+ : s2(1), // expected-warning {{field 's2' will be initialized after field 's1'}}
+ s1(1),
+ s3(3), // expected-warning {{field 's3' will be initialized after base 'BB1'}}
+ BB1(), // expected-warning {{base class 'BB1' will be initialized after base 'BB'}}
+ BB()
+ {}
int s1;
int s2;
int s3;
struct D : public A, public B {
- D() : A(), V() { } // expected-warning {{base class 'A' will be initialized after}} \
- // expected-note {{base 'V'}}
+ D() : A(), V() { } // expected-warning {{base class 'A' will be initialized after base 'V'}}
};
struct E : public A, public B, private virtual V {
- E() : A(), V() { } // expected-warning {{base class 'A' will be initialized after}} \
- // expected-note {{base 'V'}}
+ E() : A(), V() { } // expected-warning {{base class 'A' will be initialized after base 'V'}}
};
};
struct F : public A1, public B1, private virtual V {
- F() : A1(), V() { } // expected-warning {{base class 'A1' will be initialized after}} \
- // expected-note {{base 'V'}}
+ F() : A1(), V() { } // expected-warning {{base class 'A1' will be initialized after base 'V'}}
};
struct X : public virtual A, virtual V, public virtual B {
- X(): A(), V(), B() {} // expected-warning {{base class 'A' will be initialized after}} \
- // expected-note {{base 'V'}}
+ X(): A(), V(), B() {} // expected-warning {{base class 'A' will be initialized after base 'V'}}
};
class Anon {
class Anon2 {
int c; union {int a,b;}; int d;
Anon2() : c(2),
- d(10), // expected-warning {{member 'd' will be initialized after}}
- b(1) {} // expected-note {{field b}}
+ d(10), // expected-warning {{field 'd' will be initialized after field 'b'}}
+ b(1) {}
};
class Anon3 {
union {int a,b;};
struct S3 { };
struct S4: virtual S3, S2 {
- S4() : S2(), // expected-warning {{base class 'T1::S2' will be initialized after}}
- S3() { }; // expected-note {{base 'T1::S3'}}
+ S4() : S2(), // expected-warning {{base class 'T1::S2' will be initialized after base 'T1::S3'}}
+ S3() { };
};
}
+
+namespace test2 {
+ struct Foo { Foo(); };
+ class A {
+ template <class T> A(T *t) :
+ y(), // expected-warning {{field 'y' will be initialized after field 'x'}}
+ x()
+ {}
+ Foo x;
+ Foo y;
+ };
+}