diff options
author | Reid Kleckner <reid@kleckner.net> | 2014-11-17 23:36:45 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2014-11-17 23:36:45 +0000 |
commit | d60b82f93eee090650d848c45f34dcf9d3ffa0ea (patch) | |
tree | 248e4025074de0fb3c720dbad97942efe0d18b08 /clang/lib/Sema/SemaDeclCXX.cpp | |
parent | f39c3b8108c34148e6f03cbd0907619020c1a9eb (diff) | |
download | bcm5719-llvm-d60b82f93eee090650d848c45f34dcf9d3ffa0ea.tar.gz bcm5719-llvm-d60b82f93eee090650d848c45f34dcf9d3ffa0ea.zip |
Handle use of default member initializers before end of outermost class
Specifically, when we have this situation:
struct A {
template <typename T> struct B {
int m1 = sizeof(A);
};
B<int> m2;
};
We can't parse m1's initializer eagerly because we need A to be
complete. Therefore we wait until the end of A's class scope to parse
it. However, we can trigger instantiation of B before the end of A,
which will attempt to instantiate the field decls eagerly, and it would
build a bad field decl instantiation that said it had an initializer but
actually lacked one.
Fixed by deferring instantiation of default member initializers until
they are needed during constructor analysis. This addresses a long
standing FIXME in the code.
Fixes PR19195.
Reviewed By: rsmith
Differential Revision: http://reviews.llvm.org/D5690
llvm-svn: 222192
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 90 |
1 files changed, 61 insertions, 29 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c960f54b94a..6e9e7a83752 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -36,6 +36,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include <map> @@ -3730,19 +3731,19 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, return false; if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) { - Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, - Info.Ctor->getLocation(), Field); + ExprResult DIE = + SemaRef.BuildCXXDefaultInitExpr(Info.Ctor->getLocation(), Field); + if (DIE.isInvalid()) + return true; CXXCtorInitializer *Init; if (Indirect) - Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, - SourceLocation(), - SourceLocation(), DIE, - SourceLocation()); + Init = new (SemaRef.Context) + CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(), + SourceLocation(), DIE.get(), SourceLocation()); else - Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, - SourceLocation(), - SourceLocation(), DIE, - SourceLocation()); + Init = new (SemaRef.Context) + CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(), + SourceLocation(), DIE.get(), SourceLocation()); return Info.addFieldInitializer(Init); } @@ -8579,22 +8580,6 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, if (F->hasInClassInitializer()) { if (Expr *E = F->getInClassInitializer()) ExceptSpec.CalledExpr(E); - else if (!F->isInvalidDecl()) - // DR1351: - // If the brace-or-equal-initializer of a non-static data member - // invokes a defaulted default constructor of its class or of an - // enclosing class in a potentially evaluated subexpression, the - // program is ill-formed. - // - // This resolution is unworkable: the exception specification of the - // default constructor can be needed in an unevaluated context, in - // particular, in the operand of a noexcept-expression, and we can be - // unable to compute an exception specification for an enclosed class. - // - // We do not allow an in-class initializer to require the evaluation - // of the exception specification for any in-class initializer whose - // definition is not lexically complete. - Diag(Loc, diag::err_in_class_initializer_references_def_ctor) << MD; } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -8662,9 +8647,6 @@ Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) { if (F->hasInClassInitializer()) { if (Expr *E = F->getInClassInitializer()) ExceptSpec.CalledExpr(E); - else if (!F->isInvalidDecl()) - Diag(CD->getLocation(), - diag::err_in_class_initializer_references_def_ctor) << CD; } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -11129,6 +11111,56 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, ParenRange); } +ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { + assert(Field->hasInClassInitializer()); + + // If we already have the in-class initializer nothing needs to be done. + if (Field->getInClassInitializer()) + return CXXDefaultInitExpr::Create(Context, Loc, Field); + + // Maybe we haven't instantiated the in-class initializer. Go check the + // pattern FieldDecl to see if it has one. + CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent()); + + if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) { + CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); + DeclContext::lookup_result Lookup = + ClassPattern->lookup(Field->getDeclName()); + assert(Lookup.size() == 1); + FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]); + if (InstantiateInClassInitializer(Loc, Field, Pattern, + getTemplateInstantiationArgs(Field))) + return ExprError(); + return CXXDefaultInitExpr::Create(Context, Loc, Field); + } + + // DR1351: + // If the brace-or-equal-initializer of a non-static data member + // invokes a defaulted default constructor of its class or of an + // enclosing class in a potentially evaluated subexpression, the + // program is ill-formed. + // + // This resolution is unworkable: the exception specification of the + // default constructor can be needed in an unevaluated context, in + // particular, in the operand of a noexcept-expression, and we can be + // unable to compute an exception specification for an enclosed class. + // + // Any attempt to resolve the exception specification of a defaulted default + // constructor before the initializer is lexically complete will ultimately + // come here at which point we can diagnose it. + RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext(); + if (OutermostClass == ParentRD) { + Diag(Field->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed) + << ParentRD << Field; + } else { + Diag(Field->getLocEnd(), + diag::err_in_class_initializer_not_yet_parsed_outer_class) + << ParentRD << OutermostClass << Field; + } + + return ExprError(); +} + void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { if (VD->isInvalidDecl()) return; |