Diagnose misordered initializers in constructor templates immediately instead of

when they're instantiated.  Merge the note into the -Wreorder warning;  it
doesn't really contribute much, and it was splitting a thought across diagnostics
anyway.  Don't crash in the parser when a constructor's initializers end in a
comma and there's no body;  the recovery here is still terrible, but anything's
better than a crash.

llvm-svn: 100922
This commit is contained in:
John McCall 2010-04-10 07:37:23 +00:00
parent d394aec87d
commit bb7b658ab5
7 changed files with 107 additions and 93 deletions

View File

@ -2471,14 +2471,10 @@ def err_mem_init_not_member_or_class : Error<
"member initializer %0 does not name a non-static data member or base "
"class">;
def warn_field_initialized : Warning<
"member '%0' will be initialized after">,
def warn_initializer_out_of_order : Warning<
"%select{field|base class}0 %1 will be initialized after "
"%select{field|base}2 %3">,
InGroup<Reorder>, DefaultIgnore;
def warn_base_initialized : Warning<
"base class %0 will be initialized after">,
InGroup<Reorder>, DefaultIgnore;
def note_fieldorbase_initialized_here : Note<
"%select{field|base}0 %1">;
def err_base_init_does_not_name_class : Error<
"constructor initializer %0 does not name a class">;

View File

@ -217,12 +217,17 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
"ParseFunctionTryBlock left tokens in the token stream!");
continue;
}
if (Tok.is(tok::colon))
if (Tok.is(tok::colon)) {
ParseConstructorInitializer(LM.D);
else
// Error recovery.
if (!Tok.is(tok::l_brace)) {
Actions.ActOnFinishFunctionBody(LM.D, Action::StmtArg(Actions));
continue;
}
} else
Actions.ActOnDefaultCtorInitializers(LM.D);
// FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
ParseFunctionStatementBody(LM.D);
assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
Tok.getLocation()) &&

View File

@ -668,9 +668,15 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// If we have a colon, then we're probably parsing a C++
// ctor-initializer.
if (Tok.is(tok::colon))
if (Tok.is(tok::colon)) {
ParseConstructorInitializer(Res);
else
// Recover from error.
if (!Tok.is(tok::l_brace)) {
Actions.ActOnFinishFunctionBody(Res, Action::StmtArg(Actions));
return Res;
}
} else
Actions.ActOnDefaultCtorInitializers(Res);
return ParseFunctionStatementBody(Res);

View File

@ -1433,7 +1433,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
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) {
@ -1672,86 +1672,85 @@ static void *GetKeyForMember(ASTContext &Context,
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;
}
}

View File

@ -87,12 +87,11 @@ struct Derived : Base, Base1, virtual V {
struct Current : Derived {
int Derived;
Current() : Derived(1), ::Derived(), // expected-warning {{member 'Derived' will be initialized after}} \
// expected-note {{base '::Derived'}} \
// expected-warning {{base class '::Derived' will be initialized after}}
Current() : Derived(1), ::Derived(), // expected-warning {{field 'Derived' will be initialized after base '::Derived'}} \
// expected-warning {{base class '::Derived' will be initialized after base 'Derived::V'}}
::Derived::Base(), // expected-error {{type '::Derived::Base' is not a direct or virtual base of 'Current'}}
Derived::Base1(), // expected-error {{type 'Derived::Base1' is not a direct or virtual base of 'Current'}}
Derived::V(), // expected-note {{base 'Derived::V'}}
Derived::V(),
::NonExisting(), // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
INT::NonExisting() {} // expected-error {{expected a class or namespace}} \
// expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}

View File

@ -6,12 +6,13 @@ struct BB1 {};
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;
@ -44,14 +45,12 @@ struct C : public A, public B, private virtual V {
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'}}
};
@ -64,13 +63,11 @@ struct B1 {
};
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 {
@ -80,8 +77,8 @@ 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;};
@ -95,7 +92,19 @@ struct S2: virtual S1 { };
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;
};
}

View File

@ -10,8 +10,8 @@ A<int> a0;
A<void*> a1; // expected-note{{in instantiation of member function 'A<void *>::A' requested here}}
template<typename T> struct B {
B() : b(1), // expected-warning {{member 'b' will be initialized after}}
a(2) { } // expected-note {{field a}}
B() : b(1), // expected-warning {{field 'b' will be initialized after field 'a'}}
a(2) { }
int a;
int b;