[cfe-commits] [PATCH] Refactor/fix some issues with templates and member initializers
Eli Friedman
eli.friedman at gmail.com
Sat Jul 25 18:13:58 PDT 2009
Patch attached. Fixes all the testcases in PR4621.
This change refactors ActOnMemInitializer so the relevant code can be
called from template instantiation (although I haven't added the
appropriate code). It adds appropriate checks for arguments with
dependent types. It also fixes some broken logic for member
initializers which would reject initializing a member with a dependent
type.
I've attached both a regular diff and a diff -w because the latter is
a bit easier to read; I ended up reindenting a lot of the code.
(I decided to submit the patch instead of just committing it because
I'm not sure this is the right approach.)
-Eli
-------------- next part --------------
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp (revision 77084)
+++ lib/Sema/SemaDeclCXX.cpp (working copy)
@@ -716,28 +716,9 @@
// 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 @@
<< 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;
+ }
+ // 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;
+
+ // 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);
}
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h (revision 77084)
+++ lib/Sema/Sema.h (working copy)
@@ -1922,6 +1922,15 @@
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,
-------------- next part --------------
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp (revision 77084)
+++ lib/Sema/SemaDeclCXX.cpp (working copy)
@@ -716,19 +716,46 @@
// FIXME: Handle members of an anonymous union.
- if (Member) {
+ 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
+ : getTypeName(*MemberOrBase, IdLoc, S, &SS);
+ if (!BaseTy)
+ return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
+ << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+
+ QualType BaseType = QualType::getFromOpaquePtr(BaseTy);
+
+ 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() && FieldType->getAsRecordType())
+ 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)
+ } else if (NumArgs != 1) {
return Diag(IdLoc, diag::err_mem_initializer_mismatch)
- << MemberOrBase << SourceRange(IdLoc, RParenLoc);
- else {
+ << Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
+ } else if (!HasDependentArg) {
Expr * NewExp = (Expr*)Args[0];
if (PerformCopyInitialization(NewExp, FieldType, "passing"))
return true;
@@ -738,16 +765,17 @@
return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args,
NumArgs, C, IdLoc);
}
- }
- // It didn't name a member, so see if it names a class.
- TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy
- : getTypeName(*MemberOrBase, IdLoc, S, &SS);
- if (!BaseTy)
- return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
- << MemberOrBase << SourceRange(IdLoc, RParenLoc);
- QualType BaseType = QualType::getFromOpaquePtr(BaseTy);
- if (!BaseType->isRecordType() && !BaseType->isDependentType())
+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);
@@ -760,8 +788,8 @@
// 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) {
+ 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
@@ -797,7 +825,7 @@
// class, the mem-initializer is ill-formed.
if (DirectBaseSpec && VirtualBaseSpec)
return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
- << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+ << 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
@@ -806,14 +834,16 @@
return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
<< BaseType << ClassDecl->getNameAsCString()
<< SourceRange(IdLoc, RParenLoc);
- DeclarationName Name
- = Context.DeclarationNames.getCXXConstructorName(
+ }
+
+ CXXConstructorDecl *C = 0;
+ if (!BaseType->isDependentType() && !HasDependentArg) {
+ 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);
+ C = PerformInitializationByConstructor(BaseType, (Expr **)Args, NumArgs,
+ IdLoc, SourceRange(IdLoc, RParenLoc),
+ Name, IK_Direct);
+ }
return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
NumArgs, C, IdLoc);
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h (revision 77084)
+++ lib/Sema/Sema.h (working copy)
@@ -1922,6 +1922,15 @@
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,
More information about the cfe-commits
mailing list