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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100922 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 87e22fa..5b54524 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -217,12 +217,17 @@
"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()) &&
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 5c31c1d..6dbb99e 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -668,9 +668,15 @@
// 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);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 3eb8713..bc8b7d6 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1433,7 +1433,7 @@
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
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;
}
}