From 59c04373c6a4fef5c6341a21ac847d4b3a25ee36 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Wed, 29 Jul 2009 19:44:27 +0000 Subject: [PATCH] Refactor base/member initializers, and construct them correctly in cases with dependent types. Fixes PR4621 and PR4627. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77498 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 9 + lib/Sema/SemaDeclCXX.cpp | 196 ++++++++++-------- .../dependent-base-member-init.cpp | 25 +++ 3 files changed, 147 insertions(+), 83 deletions(-) create mode 100644 test/SemaTemplate/dependent-base-member-init.cpp diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b98f27f37e..960ad879f9 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1925,6 +1925,15 @@ public: SourceLocation *CommaLocs, SourceLocation RParenLoc); + MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args, + unsigned NumArgs, SourceLocation IdLoc, + SourceLocation RParenLoc); + + MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args, + unsigned NumArgs, SourceLocation IdLoc, + SourceLocation RParenLoc, + CXXRecordDecl *ClassDecl); + void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 7b0c9c6ca4..0d00955489 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -716,28 +716,9 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // FIXME: Handle members of an anonymous union. - if (Member) { - CXXConstructorDecl *C = 0; - QualType FieldType = Member->getType(); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (!FieldType->isDependentType() && FieldType->getAsRecordType()) - C = PerformInitializationByConstructor( - FieldType, (Expr **)Args, NumArgs, IdLoc, - SourceRange(IdLoc, RParenLoc), Member->getDeclName(), IK_Direct); - else if (NumArgs != 1) - return Diag(IdLoc, diag::err_mem_initializer_mismatch) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); - else { - Expr * NewExp = (Expr*)Args[0]; - if (PerformCopyInitialization(NewExp, FieldType, "passing")) - return true; - Args[0] = NewExp; - } - // FIXME: Perform direct initialization of the member. - return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, - NumArgs, C, IdLoc); - } + if (Member) + return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, + RParenLoc); } // It didn't name a member, so see if it names a class. TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy @@ -747,75 +728,124 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, << MemberOrBase << SourceRange(IdLoc, RParenLoc); QualType BaseType = QualType::getFromOpaquePtr(BaseTy); - if (!BaseType->isRecordType() && !BaseType->isDependentType()) - return Diag(IdLoc, diag::err_base_init_does_not_name_class) - << BaseType << SourceRange(IdLoc, RParenLoc); - // C++ [class.base.init]p2: - // [...] Unless the mem-initializer-id names a nonstatic data - // member of the constructor’s class or a direct or virtual base - // of that class, the mem-initializer is ill-formed. A - // mem-initializer-list can initialize a base class using any - // name that denotes that base class type. - - // First, check for a direct base class. - const CXXBaseSpecifier *DirectBaseSpec = 0; - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - if (Context.getCanonicalType(BaseType).getUnqualifiedType() == - Context.getCanonicalType(Base->getType()).getUnqualifiedType()) { - // We found a direct base of this type. That's what we're - // initializing. - DirectBaseSpec = &*Base; - break; - } + return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc, + RParenLoc, ClassDecl); +} + +Sema::MemInitResult +Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, + unsigned NumArgs, SourceLocation IdLoc, + SourceLocation RParenLoc) { + bool HasDependentArg = false; + for (unsigned i = 0; i < NumArgs; i++) + HasDependentArg |= Args[i]->isTypeDependent(); + + CXXConstructorDecl *C = 0; + QualType FieldType = Member->getType(); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (FieldType->isDependentType()) { + // Can't check init for dependent type. + } else if (FieldType->getAsRecordType()) { + if (!HasDependentArg) + C = PerformInitializationByConstructor( + FieldType, (Expr **)Args, NumArgs, IdLoc, + SourceRange(IdLoc, RParenLoc), Member->getDeclName(), IK_Direct); + } else if (NumArgs != 1) { + return Diag(IdLoc, diag::err_mem_initializer_mismatch) + << Member->getDeclName() << SourceRange(IdLoc, RParenLoc); + } else if (!HasDependentArg) { + Expr *NewExp = (Expr*)Args[0]; + if (PerformCopyInitialization(NewExp, FieldType, "passing")) + return true; + Args[0] = NewExp; } - - // Check for a virtual base class. - // FIXME: We might be able to short-circuit this if we know in advance that - // there are no virtual bases. - const CXXBaseSpecifier *VirtualBaseSpec = 0; - if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) { - // We haven't found a base yet; search the class hierarchy for a - // virtual base class. - BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) { - for (BasePaths::paths_iterator Path = Paths.begin(); - Path != Paths.end(); ++Path) { - if (Path->back().Base->isVirtual()) { - VirtualBaseSpec = Path->back().Base; - break; + // FIXME: Perform direct initialization of the member. + return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, + NumArgs, C, IdLoc); +} + +Sema::MemInitResult +Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, + unsigned NumArgs, SourceLocation IdLoc, + SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) { + bool HasDependentArg = false; + for (unsigned i = 0; i < NumArgs; i++) + HasDependentArg |= Args[i]->isTypeDependent(); + + if (!BaseType->isDependentType()) { + if (!BaseType->isRecordType()) + return Diag(IdLoc, diag::err_base_init_does_not_name_class) + << BaseType << SourceRange(IdLoc, RParenLoc); + + // C++ [class.base.init]p2: + // [...] Unless the mem-initializer-id names a nonstatic data + // member of the constructor’s class or a direct or virtual base + // of that class, the mem-initializer is ill-formed. A + // mem-initializer-list can initialize a base class using any + // name that denotes that base class type. + + // First, check for a direct base class. + const CXXBaseSpecifier *DirectBaseSpec = 0; + for (CXXRecordDecl::base_class_const_iterator Base = + ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) { + if (Context.getCanonicalType(BaseType).getUnqualifiedType() == + Context.getCanonicalType(Base->getType()).getUnqualifiedType()) { + // We found a direct base of this type. That's what we're + // initializing. + DirectBaseSpec = &*Base; + break; + } + } + + // Check for a virtual base class. + // FIXME: We might be able to short-circuit this if we know in advance that + // there are no virtual bases. + const CXXBaseSpecifier *VirtualBaseSpec = 0; + if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) { + // We haven't found a base yet; search the class hierarchy for a + // virtual base class. + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) { + for (BasePaths::paths_iterator Path = Paths.begin(); + Path != Paths.end(); ++Path) { + if (Path->back().Base->isVirtual()) { + VirtualBaseSpec = Path->back().Base; + break; + } } } } + + // C++ [base.class.init]p2: + // If a mem-initializer-id is ambiguous because it designates both + // a direct non-virtual base class and an inherited virtual base + // class, the mem-initializer is ill-formed. + if (DirectBaseSpec && VirtualBaseSpec) + return Diag(IdLoc, diag::err_base_init_direct_and_virtual) + << BaseType << SourceRange(IdLoc, RParenLoc); + // C++ [base.class.init]p2: + // Unless the mem-initializer-id names a nonstatic data membeer of the + // constructor's class ot a direst or virtual base of that class, the + // mem-initializer is ill-formed. + if (!DirectBaseSpec && !VirtualBaseSpec) + return Diag(IdLoc, diag::err_not_direct_base_or_virtual) + << BaseType << ClassDecl->getNameAsCString() + << SourceRange(IdLoc, RParenLoc); } - // C++ [base.class.init]p2: - // If a mem-initializer-id is ambiguous because it designates both - // a direct non-virtual base class and an inherited virtual base - // class, the mem-initializer is ill-formed. - if (DirectBaseSpec && VirtualBaseSpec) - return Diag(IdLoc, diag::err_base_init_direct_and_virtual) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); - // C++ [base.class.init]p2: - // Unless the mem-initializer-id names a nonstatic data membeer of the - // constructor's class ot a direst or virtual base of that class, the - // mem-initializer is ill-formed. - if (!DirectBaseSpec && !VirtualBaseSpec) - return Diag(IdLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() - << SourceRange(IdLoc, RParenLoc); - DeclarationName Name - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(BaseType)); CXXConstructorDecl *C = 0; - if (!BaseType->isDependentType()) - C = PerformInitializationByConstructor(BaseType, (Expr **)Args, NumArgs, IdLoc, - SourceRange(IdLoc, RParenLoc), Name, - IK_Direct); - - return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, + if (!BaseType->isDependentType() && !HasDependentArg) { + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(BaseType)); + C = PerformInitializationByConstructor(BaseType, (Expr **)Args, NumArgs, + IdLoc, SourceRange(IdLoc, RParenLoc), + Name, IK_Direct); + } + + return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs, C, IdLoc); } diff --git a/test/SemaTemplate/dependent-base-member-init.cpp b/test/SemaTemplate/dependent-base-member-init.cpp new file mode 100644 index 0000000000..fef945da25 --- /dev/null +++ b/test/SemaTemplate/dependent-base-member-init.cpp @@ -0,0 +1,25 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// PR4621 +class A1 { + A1(int x) {} +}; +template class B1 : public A1 { + B1(C x) : A1(x.x) {} +}; +class A2 { A2(int x, int y); }; +template class B2 { + A2 x; + B2(C x) : x(x.x, x.y) {} +}; +template class B3 { + C x; + B3() : x(1,2) {} +}; + +// PR4627 +template class insert_iterator { + _Container* container; + insert_iterator(_Container& __x) : container(&__x) {} +}; + -- 2.40.0