diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 4b7015caec57281a47989b24f7d5c0b2e86a5c81..d7103219393b4cd0d434b0cbe3f9f211967111ec 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4915,8 +4915,6 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(Scope *S, // If the class definition does not explicitly declare a copy // constructor, one is declared implicitly. - // FIXME: virtual bases! - // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will // have the form @@ -4933,6 +4931,20 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(Scope *S, BaseEnd = ClassDecl->bases_end(); HasConstCopyConstructor && Base != BaseEnd; ++Base) { + // Virtual bases are handled below. + if (Base->isVirtual()) + continue; + + const CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + HasConstCopyConstructor + = BaseClassDecl->hasConstCopyConstructor(Context); + } + + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), + BaseEnd = ClassDecl->vbases_end(); + HasConstCopyConstructor && Base != BaseEnd; + ++Base) { const CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); HasConstCopyConstructor @@ -4947,14 +4959,12 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(Scope *S, FieldEnd = ClassDecl->field_end(); HasConstCopyConstructor && Field != FieldEnd; ++Field) { - QualType FieldType = (*Field)->getType(); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); + QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (const RecordType *FieldClassType = FieldType->getAs()) { const CXXRecordDecl *FieldClassDecl - = cast(FieldClassType->getDecl()); + = cast(FieldClassType->getDecl()); HasConstCopyConstructor - = FieldClassDecl->hasConstCopyConstructor(Context); + = FieldClassDecl->hasConstCopyConstructor(Context); } } diff --git a/clang/test/CXX/special/class.copy/p9.cpp b/clang/test/CXX/special/class.copy/p9.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d03794420e01b10f80c09cda33da54064a2deab9 --- /dev/null +++ b/clang/test/CXX/special/class.copy/p9.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct ConstCopy { + ConstCopy(); + ConstCopy(const ConstCopy&); +}; + +struct NonConstCopy { + NonConstCopy(); + NonConstCopy(NonConstCopy&); +}; + +struct VirtualInheritsNonConstCopy : virtual NonConstCopy { + VirtualInheritsNonConstCopy(); + VirtualInheritsNonConstCopy(const VirtualInheritsNonConstCopy&); +}; + +struct ImplicitNonConstCopy1 : NonConstCopy { + ImplicitNonConstCopy1(); +}; + +struct ImplicitNonConstCopy2 { + ImplicitNonConstCopy2(); + NonConstCopy ncc; +}; + +struct ImplicitNonConstCopy3 { + ImplicitNonConstCopy3(); + NonConstCopy ncc_array[2][3]; +}; + +struct ImplicitNonConstCopy4 : VirtualInheritsNonConstCopy { + ImplicitNonConstCopy4(); +}; + +void test_non_const_copy(const ImplicitNonConstCopy1 &cincc1, + const ImplicitNonConstCopy2 &cincc2, + const ImplicitNonConstCopy3 &cincc3, + const ImplicitNonConstCopy4 &cincc4) { + (void)sizeof(ImplicitNonConstCopy1(cincc1)); // expected-error{{functional-style cast from 'ImplicitNonConstCopy1 const' to 'ImplicitNonConstCopy1' is not allowed}} + (void)sizeof(ImplicitNonConstCopy2(cincc2)); // expected-error{{functional-style cast from 'ImplicitNonConstCopy2 const' to 'ImplicitNonConstCopy2' is not allowed}} + (void)sizeof(ImplicitNonConstCopy3(cincc3)); // expected-error{{functional-style cast from 'ImplicitNonConstCopy3 const' to 'ImplicitNonConstCopy3' is not allowed}} + (void)sizeof(ImplicitNonConstCopy4(cincc4)); // expected-error{{functional-style cast from 'ImplicitNonConstCopy4 const' to 'ImplicitNonConstCopy4' is not allowed}} +}