[cfe-commits] r169667 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Sema/ test/CXX/basic/basic.types/ test/CXX/class/class.union/ test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/ test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/ test/CXX/special/class.copy/ test/CXX/special/class.ctor/ test/SemaCXX/
Richard Smith
richard-llvm at metafoo.co.uk
Fri Dec 7 18:53:03 PST 2012
Author: rsmith
Date: Fri Dec 7 20:53:02 2012
New Revision: 169667
URL: http://llvm.org/viewvc/llvm-project?rev=169667&view=rev
Log:
Properly compute triviality for explicitly-defaulted or deleted special members.
Remove pre-standard restriction on explicitly-defaulted copy constructors with
'incorrect' parameter types, and instead just make those special members
non-trivial as the standard requires.
This required making CXXRecordDecl correctly handle classes which have both a
trivial and a non-trivial special member of the same kind.
This also fixes PR13217 by reimplementing DiagnoseNontrivial in terms of the
new triviality computation technology.
Added:
cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp
cfe/trunk/test/CXX/special/class.copy/p25-0x.cpp
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/CXX/basic/basic.types/p10.cpp
cfe/trunk/test/CXX/class/class.union/p1.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp
cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp
cfe/trunk/test/SemaCXX/anonymous-struct.cpp
cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp
cfe/trunk/test/SemaCXX/cxx98-compat.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Fri Dec 7 20:53:02 2012
@@ -1736,7 +1736,7 @@
/// Whether this is a (C++11) constexpr function or constexpr constructor.
bool isConstexpr() const { return IsConstexpr; }
- void setConstexpr(bool IC);
+ void setConstexpr(bool IC) { IsConstexpr = IC; }
/// \brief Whether this function has been deleted.
///
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Dec 7 20:53:02 2012
@@ -360,9 +360,20 @@
/// \brief The trivial special members which this class has, per
/// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25,
- /// C++11 [class.dtor]p5.
+ /// C++11 [class.dtor]p5, or would have if the member were not suppressed.
+ ///
+ /// This excludes any user-declared but not user-provided special members
+ /// which have been declared but not yet defined.
unsigned HasTrivialSpecialMembers : 6;
+ /// \brief The declared special members of this class which are known to be
+ /// non-trivial.
+ ///
+ /// This excludes any user-declared but not user-provided special members
+ /// which have been declared but not yet defined, and any implicit special
+ /// members which have not yet been declared.
+ unsigned DeclaredNonTrivialSpecialMembers : 6;
+
/// HasIrrelevantDestructor - True when this class has a destructor with no
/// semantic effect.
bool HasIrrelevantDestructor : 1;
@@ -565,9 +576,6 @@
void markedVirtualFunctionPure();
friend void FunctionDecl::setPure(bool);
- void markedConstructorConstexpr(CXXConstructorDecl *CD);
- friend void FunctionDecl::setConstexpr(bool);
-
friend class ASTNodeImporter;
protected:
@@ -1035,7 +1043,6 @@
/// \brief Determine whether this class has a trivial default constructor
/// (C++11 [class.ctor]p5).
- /// FIXME: This can be wrong when the class has multiple default constructors.
bool hasTrivialDefaultConstructor() const {
return hasDefaultConstructor() &&
(data().HasTrivialSpecialMembers & SMF_DefaultConstructor);
@@ -1044,8 +1051,9 @@
/// \brief Determine whether this class has a non-trivial default constructor
/// (C++11 [class.ctor]p5).
bool hasNonTrivialDefaultConstructor() const {
- return hasDefaultConstructor() &&
- !(data().HasTrivialSpecialMembers & SMF_DefaultConstructor);
+ return (data().DeclaredNonTrivialSpecialMembers & SMF_DefaultConstructor) ||
+ (needsImplicitDefaultConstructor() &&
+ !(data().HasTrivialSpecialMembers & SMF_DefaultConstructor));
}
/// \brief Determine whether this class has at least one constexpr constructor
@@ -1072,7 +1080,6 @@
/// \brief Determine whether this class has a trivial copy constructor
/// (C++ [class.copy]p6, C++11 [class.copy]p12)
- /// FIXME: This can be wrong if the class has multiple copy constructors.
bool hasTrivialCopyConstructor() const {
return data().HasTrivialSpecialMembers & SMF_CopyConstructor;
}
@@ -1080,13 +1087,14 @@
/// \brief Determine whether this class has a non-trivial copy constructor
/// (C++ [class.copy]p6, C++11 [class.copy]p12)
bool hasNonTrivialCopyConstructor() const {
- return !(data().HasTrivialSpecialMembers & SMF_CopyConstructor);
+ return data().DeclaredNonTrivialSpecialMembers & SMF_CopyConstructor ||
+ !hasTrivialCopyConstructor();
}
/// \brief Determine whether this class has a trivial move constructor
/// (C++11 [class.copy]p12)
- /// FIXME: This can be wrong if the class has multiple move constructors,
- /// or if the implicit move constructor would be deleted.
+ /// FIXME: This can be wrong if the implicit move constructor would be
+ /// deleted.
bool hasTrivialMoveConstructor() const {
return hasMoveConstructor() &&
(data().HasTrivialSpecialMembers & SMF_MoveConstructor);
@@ -1097,14 +1105,13 @@
/// FIXME: This can be wrong if the implicit move constructor would be
/// deleted.
bool hasNonTrivialMoveConstructor() const {
- return hasMoveConstructor() &&
- !(data().HasTrivialSpecialMembers & SMF_MoveConstructor);
+ return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) ||
+ (needsImplicitMoveConstructor() &&
+ !(data().HasTrivialSpecialMembers & SMF_MoveConstructor));
}
/// \brief Determine whether this class has a trivial copy assignment operator
/// (C++ [class.copy]p11, C++11 [class.copy]p25)
- /// FIXME: This can be wrong if the class has multiple copy assignment
- /// operators.
bool hasTrivialCopyAssignment() const {
return data().HasTrivialSpecialMembers & SMF_CopyAssignment;
}
@@ -1112,13 +1119,13 @@
/// \brief Determine whether this class has a non-trivial copy assignment
/// operator (C++ [class.copy]p11, C++11 [class.copy]p25)
bool hasNonTrivialCopyAssignment() const {
- return !(data().HasTrivialSpecialMembers & SMF_CopyAssignment);
+ return data().DeclaredNonTrivialSpecialMembers & SMF_CopyAssignment ||
+ !hasTrivialCopyAssignment();
}
/// \brief Determine whether this class has a trivial move assignment operator
/// (C++11 [class.copy]p25)
- /// FIXME: This can be wrong if the class has multiple move assignment
- /// operators, or if the implicit move assignment operator would be deleted.
+ /// FIXME: This can be wrong if the implicit move assignment would be deleted.
bool hasTrivialMoveAssignment() const {
return hasMoveAssignment() &&
(data().HasTrivialSpecialMembers & SMF_MoveAssignment);
@@ -1128,8 +1135,9 @@
/// operator (C++11 [class.copy]p25)
/// FIXME: This can be wrong if the implicit move assignment would be deleted.
bool hasNonTrivialMoveAssignment() const {
- return hasMoveAssignment() &&
- !(data().HasTrivialSpecialMembers & SMF_MoveAssignment);
+ return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveAssignment) ||
+ (needsImplicitMoveAssignment() &&
+ !(data().HasTrivialSpecialMembers & SMF_MoveAssignment));
}
/// \brief Determine whether this class has a trivial destructor
@@ -1447,6 +1455,10 @@
return (PathAccess > DeclAccess ? PathAccess : DeclAccess);
}
+ /// \brief Indicates that the declaration of a defaulted or deleted special
+ /// member function is now complete.
+ void finishedDefaultedOrDeletedMember(CXXMethodDecl *MD);
+
/// \brief Indicates that the definition of this class is now complete.
virtual void completeDefinition();
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Dec 7 20:53:02 2012
@@ -1073,6 +1073,7 @@
"%select{|implicit default }0constructor for %1 must explicitly initialize "
"the %select{base class|member}2 %3 which does not have a default "
"constructor">;
+
def err_illegal_union_or_anon_struct_member : Error<
"%select{anonymous struct|union}0 member %1 has a non-trivial "
"%select{constructor|copy constructor|move constructor|copy assignment "
@@ -1082,16 +1083,40 @@
"%select{constructor|copy constructor|move constructor|copy assignment "
"operator|move assignment operator|destructor}2 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+
+def note_nontrivial_virtual_dtor : Note<
+ "destructor for %0 is not trivial because it is virtual">;
def note_nontrivial_has_virtual : Note<
"because type %0 has a virtual %select{member function|base class}1">;
-def note_nontrivial_has_nontrivial : Note<
- "because type %0 has a %select{member|base class}1 with a non-trivial "
- "%select{constructor|copy constructor|move constructor|copy assignment "
- "operator|move assignment operator|destructor}2">;
-def note_nontrivial_user_defined : Note<
- "because type %0 has a user-declared %select{constructor|copy constructor|"
- "move constructor|copy assignment operator|move assignment operator|"
- "destructor}1">;
+def note_nontrivial_no_def_ctor : Note<
+ "because %select{base class of |field of |}0type %1 has no "
+ "default constructor">;
+def note_user_declared_ctor : Note<
+ "implicit default constructor suppressed by user-declared constructor">;
+def note_nontrivial_no_copy : Note<
+ "because no %select{<<ERROR>>|constructor|constructor|assignment operator|"
+ "assignment operator|<<ERROR>>}2 can be used to "
+ "%select{<<ERROR>>|copy|move|copy|move|<<ERROR>>}2 "
+ "%select{base class|field|an object}0 of type %3">;
+def note_nontrivial_user_provided : Note<
+ "because %select{base class of |field of |}0type %1 has a user-provided "
+ "%select{default constructor|copy constructor|move constructor|"
+ "copy assignment operator|move assignment operator|destructor}2">;
+def note_nontrivial_in_class_init : Note<
+ "because field %0 has an initializer">;
+def note_nontrivial_param_type : Note<
+ "because its parameter is %diff{of type $, not $|of the wrong type}2,3">;
+def note_nontrivial_default_arg : Note<"because it has a default argument">;
+def note_nontrivial_variadic : Note<"because it is a variadic function">;
+def note_nontrivial_subobject : Note<
+ "because the function selected to %select{construct|copy|move|copy|move|"
+ "destroy}2 %select{base class|field}0 of type %1 is not trivial">;
+def note_nontrivial_user_declared_ctor : Note<
+ "because type %0 has a user-declared constructor">;
+def note_nontrivial_objc_ownership : Note<
+ "because type %0 has a member with %select{no|no|__strong|__weak|"
+ "__autoreleasing}1 ownership">;
+
def err_static_data_member_not_allowed_in_anon_struct : Error<
"static data member %0 not allowed in anonymous struct">;
def ext_static_data_member_in_union : ExtWarn<
@@ -3706,9 +3731,6 @@
} // end "ARC Retain Cycle" category
-def note_nontrivial_objc_ownership : Note<
- "because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 "
- "ownership">;
def warn_arc_object_memaccess : Warning<
"%select{destination for|source of}0 this %1 call is a pointer to "
"ownership-qualified type %2">, InGroup<ARCNonPodMemAccess>;
@@ -5429,10 +5451,6 @@
"the parameter for this explicitly-defaulted copy "
"%select{constructor|assignment operator}0 is const, but a member or base "
"requires it to be non-const">;
-def err_defaulted_special_member_copy_non_const_param : Error<
- "explicitly-defaulted copy %select{constructor|assignment operator}0 with "
- "a non-const parameter must be defaulted outside the class, unless a base or "
- "member requires the parameter to be non-const">;
def err_defaulted_copy_assign_not_ref : Error<
"the parameter for an explicitly-defaulted copy assignment operator must be an "
"lvalue reference type">;
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Dec 7 20:53:02 2012
@@ -1530,7 +1530,9 @@
Declarator *D = 0);
bool CheckNontrivialField(FieldDecl *FD);
- void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
+ void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM);
+ bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose = false);
CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
void ActOnLastBitfield(SourceLocation DeclStart,
SmallVectorImpl<Decl *> &AllIvarDecls);
@@ -4438,7 +4440,7 @@
StorageClass& SC);
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
- void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record);
+ void CheckExplicitlyDefaultedAndDeletedMethods(CXXRecordDecl *Record);
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
//===--------------------------------------------------------------------===//
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Fri Dec 7 20:53:02 2012
@@ -1658,13 +1658,6 @@
Parent->markedVirtualFunctionPure();
}
-void FunctionDecl::setConstexpr(bool IC) {
- IsConstexpr = IC;
- CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(this);
- if (IC && CD)
- CD->getParent()->markedConstructorConstexpr(CD);
-}
-
bool FunctionDecl::isMain() const {
const TranslationUnitDecl *tunit =
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Dec 7 20:53:02 2012
@@ -43,6 +43,7 @@
HasMutableFields(false), HasOnlyCMembers(true),
HasInClassInitializer(false), HasUninitializedReferenceMember(false),
HasTrivialSpecialMembers(SMF_All),
+ DeclaredNonTrivialSpecialMembers(0),
HasIrrelevantDestructor(true),
HasConstexprNonCopyMoveConstructor(false),
DefaultedDefaultConstructorIsConstexpr(true),
@@ -261,7 +262,7 @@
if (!BaseClassDecl->hasConstexprDefaultConstructor())
data().DefaultedDefaultConstructorIsConstexpr = false;
}
-
+
// C++ [class.ctor]p3:
// A destructor is trivial if all the direct base classes of its class
// have trivial destructors.
@@ -470,14 +471,6 @@
data().Abstract = true;
}
-void CXXRecordDecl::markedConstructorConstexpr(CXXConstructorDecl *CD) {
- if (!CD->isCopyOrMoveConstructor())
- data().HasConstexprNonCopyMoveConstructor = true;
-
- if (CD->isDefaultConstructor())
- data().HasConstexprDefaultConstructor = true;
-}
-
void CXXRecordDecl::addedMember(Decl *D) {
if (!D->isImplicit() &&
!isa<FieldDecl>(D) &&
@@ -638,6 +631,20 @@
}
if (SMKind) {
+ // If this is the first declaration of a special member, we no longer have
+ // an implicit trivial special member.
+ data().HasTrivialSpecialMembers &=
+ data().DeclaredSpecialMembers | ~SMKind;
+
+ if (!Method->isImplicit() && !Method->isUserProvided()) {
+ // This method is user-declared but not user-provided. We can't work out
+ // whether it's trivial yet (not until we get to the end of the class).
+ // We'll handle this method in finishedDefaultedOrDeletedMember.
+ } else if (Method->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
+
// Note when we have declared a declared special member, and suppress the
// implicit declaration of this special member.
data().DeclaredSpecialMembers |= SMKind;
@@ -658,14 +665,6 @@
// This is an extension in C++03.
data().PlainOldData = false;
}
-
- // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25,
- // C++11 [class.dtor]p5:
- // A [special member] is trivial if it is not user-provided [...]
- // FIXME: This is bogus. A class can have both (say) a trivial copy
- // constructor *and* a user-provided copy constructor.
- if (Method->isUserProvided())
- data().HasTrivialSpecialMembers &= ~SMKind;
}
return;
@@ -910,6 +909,40 @@
data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
}
+void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
+ assert(!D->isImplicit() && !D->isUserProvided());
+
+ // The kind of special member this declaration is, if any.
+ unsigned SMKind = 0;
+
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ if (Constructor->isDefaultConstructor()) {
+ SMKind |= SMF_DefaultConstructor;
+ if (Constructor->isConstexpr())
+ data().HasConstexprDefaultConstructor = true;
+ }
+ if (Constructor->isCopyConstructor())
+ SMKind |= SMF_CopyConstructor;
+ else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
+ else if (Constructor->isConstexpr())
+ // We may now know that the constructor is constexpr.
+ data().HasConstexprNonCopyMoveConstructor = true;
+ } else if (isa<CXXDestructorDecl>(D))
+ SMKind |= SMF_Destructor;
+ else if (D->isCopyAssignmentOperator())
+ SMKind |= SMF_CopyAssignment;
+ else if (D->isMoveAssignmentOperator())
+ SMKind |= SMF_MoveAssignment;
+
+ // Update which trivial / non-trivial special members we have.
+ // addedMember will have skipped this step for this member.
+ if (D->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
+}
+
bool CXXRecordDecl::isCLike() const {
if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface ||
!TemplateOrInstantiation.isNull())
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Dec 7 20:53:02 2012
@@ -9772,7 +9772,7 @@
QualType EltTy = Context.getBaseElementType(FD->getType());
if (const RecordType *RT = EltTy->getAs<RecordType>()) {
- CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+ CXXRecordDecl *RDecl = cast<CXXRecordDecl>(RT->getDecl());
if (RDecl->getDefinition()) {
// We check for copy constructors before constructors
// because otherwise we'll never get complaints about
@@ -9814,192 +9814,13 @@
diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member :
diag::err_illegal_union_or_anon_struct_member)
<< (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
- DiagnoseNontrivial(RT, member);
+ DiagnoseNontrivial(RDecl, member);
return !getLangOpts().CPlusPlus0x;
}
}
}
-
- return false;
-}
-
-/// If the given constructor is user-declared, produce a diagnostic explaining
-/// that it makes the class non-trivial.
-static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT,
- CXXConstructorDecl *CD,
- Sema::CXXSpecialMember CSM) {
- if (CD->isImplicit())
- return false;
-
- SourceLocation CtorLoc = CD->getLocation();
- S.Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << CSM;
- return true;
-}
-
-/// DiagnoseNontrivial - Given that a class has a non-trivial
-/// special member, figure out why.
-/// FIXME: These checks are not correct in C++11 mode. Currently, this is OK
-/// since we only use this in C++11 for a -Wc++98-compat warning.
-void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
- QualType QT(T, 0U);
- CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
-
- // Check whether the member was user-declared.
- switch (member) {
- case CXXInvalid:
- break;
-
- case CXXDefaultConstructor:
- if (RD->hasUserDeclaredConstructor()) {
- typedef CXXRecordDecl::ctor_iterator ctor_iter;
- for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI)
- if (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member))
- return;
-
- // No user-delcared constructors; look for constructor templates.
- typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
- tmpl_iter;
- for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end());
- TI != TE; ++TI) {
- CXXConstructorDecl *CD =
- dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl());
- if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member))
- return;
- }
- }
- break;
-
- case CXXCopyConstructor:
- if (RD->hasUserDeclaredCopyConstructor()) {
- SourceLocation CtorLoc =
- RD->getCopyConstructor(0)->getLocation();
- Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXMoveConstructor:
- if (RD->hasUserDeclaredMoveConstructor()) {
- SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation();
- Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXCopyAssignment:
- if (RD->hasUserDeclaredCopyAssignment()) {
- SourceLocation AssignLoc =
- RD->getCopyAssignmentOperator(0)->getLocation();
- Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXMoveAssignment:
- if (RD->hasUserDeclaredMoveAssignment()) {
- SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation();
- Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXDestructor:
- if (RD->hasUserDeclaredDestructor()) {
- SourceLocation DtorLoc = LookupDestructor(RD)->getLocation();
- Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
- }
-
- typedef CXXRecordDecl::base_class_iterator base_iter;
-
- // Virtual bases and members inhibit trivial copying/construction,
- // but not trivial destruction.
- if (member != CXXDestructor) {
- // Check for virtual bases. vbases includes indirect virtual bases,
- // so we just iterate through the direct bases.
- for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi)
- if (bi->isVirtual()) {
- SourceLocation BaseLoc = bi->getLocStart();
- Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
- return;
- }
-
- // Check for virtual methods.
- typedef CXXRecordDecl::method_iterator meth_iter;
- for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi) {
- if (mi->isVirtual()) {
- SourceLocation MLoc = mi->getLocStart();
- Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
- return;
- }
- }
- }
- bool (CXXRecordDecl::*hasNonTrivial)() const;
- switch (member) {
- case CXXDefaultConstructor:
- hasNonTrivial = &CXXRecordDecl::hasNonTrivialDefaultConstructor; break;
- case CXXCopyConstructor:
- hasNonTrivial = &CXXRecordDecl::hasNonTrivialCopyConstructor; break;
- case CXXCopyAssignment:
- hasNonTrivial = &CXXRecordDecl::hasNonTrivialCopyAssignment; break;
- case CXXMoveConstructor:
- hasNonTrivial = &CXXRecordDecl::hasNonTrivialMoveConstructor; break;
- case CXXMoveAssignment:
- hasNonTrivial = &CXXRecordDecl::hasNonTrivialMoveAssignment; break;
- case CXXDestructor:
- hasNonTrivial = &CXXRecordDecl::hasNonTrivialDestructor; break;
- case CXXInvalid:
- llvm_unreachable("unexpected special member");
- }
-
- // Check for nontrivial bases (and recurse).
- for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) {
- const RecordType *BaseRT = bi->getType()->getAs<RecordType>();
- assert(BaseRT && "Don't know how to handle dependent bases");
- CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
- if ((BaseRecTy->*hasNonTrivial)()) {
- SourceLocation BaseLoc = bi->getLocStart();
- Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
- DiagnoseNontrivial(BaseRT, member);
- return;
- }
- }
-
- // Check for nontrivial members (and recurse).
- typedef RecordDecl::field_iterator field_iter;
- for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
- ++fi) {
- QualType EltTy = Context.getBaseElementType(fi->getType());
- if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
- CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
-
- if ((EltRD->*hasNonTrivial)()) {
- SourceLocation FLoc = fi->getLocation();
- Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
- DiagnoseNontrivial(EltRT, member);
- return;
- }
- }
-
- if (EltTy->isObjCLifetimeType()) {
- switch (EltTy.getObjCLifetime()) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- break;
-
- case Qualifiers::OCL_Autoreleasing:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Strong:
- Diag(fi->getLocation(), diag::note_nontrivial_objc_ownership)
- << QT << EltTy.getObjCLifetime();
- return;
- }
- }
- }
+ return false;
}
/// TranslateIvarVisibility - Translate visibility from a token ID to an
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Dec 7 20:53:02 2012
@@ -3990,42 +3990,6 @@
}
}
- // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
- // function that is not a constructor declares that member function to be
- // const. [...] The class of which that function is a member shall be
- // a literal type.
- //
- // If the class has virtual bases, any constexpr members will already have
- // been diagnosed by the checks performed on the member declaration, so
- // suppress this (less useful) diagnostic.
- if (LangOpts.CPlusPlus0x && !Record->isDependentType() &&
- !Record->isLiteral() && !Record->getNumVBases()) {
- for (CXXRecordDecl::method_iterator M = Record->method_begin(),
- MEnd = Record->method_end();
- M != MEnd; ++M) {
- if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
- switch (Record->getTemplateSpecializationKind()) {
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- // If a template instantiates to a non-literal type, but its members
- // instantiate to constexpr functions, the template is technically
- // ill-formed, but we allow it for sanity.
- continue;
-
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- RequireLiteralType(M->getLocation(), Context.getRecordType(Record),
- diag::err_constexpr_method_non_literal);
- break;
- }
-
- // Only produce one error per class.
- break;
- }
- }
- }
-
// Declare inherited constructors. We do this eagerly here because:
// - The standard requires an eager diagnostic for conflicting inherited
// constructors from different classes.
@@ -4036,12 +4000,25 @@
DeclareInheritedConstructors(Record);
}
-void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
+void Sema::CheckExplicitlyDefaultedAndDeletedMethods(CXXRecordDecl *Record) {
for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
ME = Record->method_end();
- MI != ME; ++MI)
+ MI != ME; ++MI) {
if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted())
CheckExplicitlyDefaultedSpecialMember(*MI);
+
+ if (!MI->isImplicit() && !MI->isUserProvided()) {
+ // For an explicitly defaulted or deleted special member, we defer
+ // determining triviality until the class is complete. That time is now!
+ CXXSpecialMember CSM = getSpecialMember(*MI);
+ if (CSM != CXXInvalid) {
+ MI->setTrivial(SpecialMemberIsTrivial(*MI, CSM));
+
+ // Inform the class that we've finished declaring this member.
+ Record->finishedDefaultedOrDeletedMember(*MI);
+ }
+ }
+ }
}
/// Is the special member function which would be selected to perform the
@@ -4231,33 +4208,11 @@
const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>();
- // Compute argument constness, constexpr, and triviality.
bool CanHaveConstParam = false;
- bool Trivial = false;
- switch (CSM) {
- case CXXDefaultConstructor:
- Trivial = RD->hasTrivialDefaultConstructor();
- break;
- case CXXCopyConstructor:
+ if (CSM == CXXCopyConstructor)
CanHaveConstParam = RD->implicitCopyConstructorHasConstParam();
- Trivial = RD->hasTrivialCopyConstructor();
- break;
- case CXXCopyAssignment:
+ else if (CSM == CXXCopyAssignment)
CanHaveConstParam = RD->implicitCopyAssignmentHasConstParam();
- Trivial = RD->hasTrivialCopyAssignment();
- break;
- case CXXMoveConstructor:
- Trivial = RD->hasTrivialMoveConstructor();
- break;
- case CXXMoveAssignment:
- Trivial = RD->hasTrivialMoveAssignment();
- break;
- case CXXDestructor:
- Trivial = RD->hasTrivialDestructor();
- break;
- case CXXInvalid:
- llvm_unreachable("non-special member explicitly defaulted!");
- }
QualType ReturnType = Context.VoidTy;
if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) {
@@ -4306,14 +4261,6 @@
}
HadError = true;
}
-
- // If a function is explicitly defaulted on its first declaration, it shall
- // have the same parameter type as if it had been implicitly declared.
- // (Presumably this is to prevent it from being trivial?)
- if (!HasConstParam && CanHaveConstParam && First)
- Diag(MD->getLocation(),
- diag::err_defaulted_special_member_copy_non_const_param)
- << (CSM == CXXCopyAssignment);
} else if (ExpectedParams) {
// A copy assignment operator can take its argument by value, but a
// defaulted one cannot.
@@ -4363,10 +4310,6 @@
// -- it is implicitly considered to have the same exception-specification
// as if it had been implicitly declared,
MD->setType(QualType(ImplicitType, 0));
-
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- MD->setTrivial(Trivial);
}
if (ShouldDeleteSpecialMember(MD, CSM)) {
@@ -4805,6 +4748,427 @@
return false;
}
+/// Perform lookup for a special member of the specified kind, and determine
+/// whether it is trivial. If the triviality can be determined without the
+/// lookup, skip it. This is intended for use when determining whether a
+/// special member of a containing object is trivial, and thus does not ever
+/// perform overload resolution for default constructors.
+///
+/// If \p Selected is not \c NULL, \c *Selected will be filled in with the
+/// member that was most likely to be intended to be trivial, if any.
+static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
+ Sema::CXXSpecialMember CSM, unsigned Quals,
+ CXXMethodDecl **Selected) {
+ if (Selected)
+ *Selected = 0;
+
+ switch (CSM) {
+ case Sema::CXXInvalid:
+ llvm_unreachable("not a special member");
+
+ case Sema::CXXDefaultConstructor:
+ // C++11 [class.ctor]p5:
+ // A default constructor is trivial if:
+ // - all the [direct subobjects] have trivial default constructors
+ //
+ // Note, no overload resolution is performed in this case.
+ if (RD->hasTrivialDefaultConstructor())
+ return true;
+
+ if (Selected) {
+ // If there's a default constructor which could have been trivial, dig it
+ // out. Otherwise, if there's any user-provided default constructor, point
+ // to that as an example of why there's not a trivial one.
+ CXXConstructorDecl *DefCtor = 0;
+ if (RD->needsImplicitDefaultConstructor())
+ S.DeclareImplicitDefaultConstructor(RD);
+ for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(),
+ CE = RD->ctor_end(); CI != CE; ++CI) {
+ if (!CI->isDefaultConstructor())
+ continue;
+ DefCtor = *CI;
+ if (!DefCtor->isUserProvided())
+ break;
+ }
+
+ *Selected = DefCtor;
+ }
+
+ return false;
+
+ case Sema::CXXDestructor:
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if:
+ // - all the direct [subobjects] have trivial destructors
+ if (RD->hasTrivialDestructor())
+ return true;
+
+ if (Selected) {
+ if (RD->needsImplicitDestructor())
+ S.DeclareImplicitDestructor(RD);
+ *Selected = RD->getDestructor();
+ }
+
+ return false;
+
+ case Sema::CXXCopyConstructor:
+ // C++11 [class.copy]p12:
+ // A copy constructor is trivial if:
+ // - the constructor selected to copy each direct [subobject] is trivial
+ if (RD->hasTrivialCopyConstructor()) {
+ if (Quals == Qualifiers::Const)
+ // We must either select the trivial copy constructor or reach an
+ // ambiguity; no need to actually perform overload resolution.
+ return true;
+ } else if (!Selected) {
+ return false;
+ }
+ // In C++98, we are not supposed to perform overload resolution here, but we
+ // treat that as a language defect, as suggested on cxx-abi-dev, to treat
+ // cases like B as having a non-trivial copy constructor:
+ // struct A { template<typename T> A(T&); };
+ // struct B { mutable A a; };
+ goto NeedOverloadResolution;
+
+ case Sema::CXXCopyAssignment:
+ // C++11 [class.copy]p25:
+ // A copy assignment operator is trivial if:
+ // - the assignment operator selected to copy each direct [subobject] is
+ // trivial
+ if (RD->hasTrivialCopyAssignment()) {
+ if (Quals == Qualifiers::Const)
+ return true;
+ } else if (!Selected) {
+ return false;
+ }
+ // In C++98, we are not supposed to perform overload resolution here, but we
+ // treat that as a language defect.
+ goto NeedOverloadResolution;
+
+ case Sema::CXXMoveConstructor:
+ case Sema::CXXMoveAssignment:
+ NeedOverloadResolution:
+ Sema::SpecialMemberOverloadResult *SMOR =
+ S.LookupSpecialMember(RD, CSM,
+ Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile,
+ /*RValueThis*/false, /*ConstThis*/false,
+ /*VolatileThis*/false);
+
+ // The standard doesn't describe how to behave if the lookup is ambiguous.
+ // We treat it as not making the member non-trivial, just like the standard
+ // mandates for the default constructor. This should rarely matter, because
+ // the member will also be deleted.
+ if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ return true;
+
+ if (!SMOR->getMethod()) {
+ assert(SMOR->getKind() ==
+ Sema::SpecialMemberOverloadResult::NoMemberOrDeleted);
+ return false;
+ }
+
+ // We deliberately don't check if we found a deleted special member. We're
+ // not supposed to!
+ if (Selected)
+ *Selected = SMOR->getMethod();
+ return SMOR->getMethod()->isTrivial();
+ }
+
+ llvm_unreachable("unknown special method kind");
+}
+
+CXXConstructorDecl *findUserDeclaredCtor(CXXRecordDecl *RD) {
+ for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(), CE = RD->ctor_end();
+ CI != CE; ++CI)
+ if (!CI->isImplicit())
+ return *CI;
+
+ // Look for constructor templates.
+ typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> tmpl_iter;
+ for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) {
+ if (CXXConstructorDecl *CD =
+ dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl()))
+ return CD;
+ }
+
+ return 0;
+}
+
+/// The kind of subobject we are checking for triviality. The values of this
+/// enumeration are used in diagnostics.
+enum TrivialSubobjectKind {
+ /// The subobject is a base class.
+ TSK_BaseClass,
+ /// The subobject is a non-static data member.
+ TSK_Field,
+ /// The object is actually the complete object.
+ TSK_CompleteObject
+};
+
+/// Check whether the special member selected for a given type would be trivial.
+static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc,
+ QualType SubType,
+ Sema::CXXSpecialMember CSM,
+ TrivialSubobjectKind Kind,
+ bool Diagnose) {
+ CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl();
+ if (!SubRD)
+ return true;
+
+ CXXMethodDecl *Selected;
+ if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(),
+ Diagnose ? &Selected : 0))
+ return true;
+
+ if (Diagnose) {
+ if (!Selected && CSM == Sema::CXXDefaultConstructor) {
+ S.Diag(SubobjLoc, diag::note_nontrivial_no_def_ctor)
+ << Kind << SubType.getUnqualifiedType();
+ if (CXXConstructorDecl *CD = findUserDeclaredCtor(SubRD))
+ S.Diag(CD->getLocation(), diag::note_user_declared_ctor);
+ } else if (!Selected)
+ S.Diag(SubobjLoc, diag::note_nontrivial_no_copy)
+ << Kind << SubType.getUnqualifiedType() << CSM << SubType;
+ else if (Selected->isUserProvided()) {
+ if (Kind == TSK_CompleteObject)
+ S.Diag(Selected->getLocation(), diag::note_nontrivial_user_provided)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+ else {
+ S.Diag(SubobjLoc, diag::note_nontrivial_user_provided)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+ S.Diag(Selected->getLocation(), diag::note_declared_at);
+ }
+ } else {
+ if (Kind != TSK_CompleteObject)
+ S.Diag(SubobjLoc, diag::note_nontrivial_subobject)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+
+ // Explain why the defaulted or deleted special member isn't trivial.
+ S.SpecialMemberIsTrivial(Selected, CSM, Diagnose);
+ }
+ }
+
+ return false;
+}
+
+/// Check whether the members of a class type allow a special member to be
+/// trivial.
+static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
+ Sema::CXXSpecialMember CSM,
+ bool ConstArg, bool Diagnose) {
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end(); FI != FE; ++FI) {
+ if (FI->isInvalidDecl() || FI->isUnnamedBitfield())
+ continue;
+
+ QualType FieldType = S.Context.getBaseElementType(FI->getType());
+
+ // Pretend anonymous struct or union members are members of this class.
+ if (FI->isAnonymousStructOrUnion()) {
+ if (!checkTrivialClassMembers(S, FieldType->getAsCXXRecordDecl(),
+ CSM, ConstArg, Diagnose))
+ return false;
+ continue;
+ }
+
+ // C++11 [class.ctor]p5:
+ // A default constructor is trivial if [...]
+ // -- no non-static data member of its class has a
+ // brace-or-equal-initializer
+ if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) {
+ if (Diagnose)
+ S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << *FI;
+ return false;
+ }
+
+ // Objective C ARC 4.3.5:
+ // [...] nontrivally ownership-qualified types are [...] not trivially
+ // default constructible, copy constructible, move constructible, copy
+ // assignable, move assignable, or destructible [...]
+ if (S.getLangOpts().ObjCAutoRefCount &&
+ FieldType.hasNonTrivialObjCLifetime()) {
+ if (Diagnose)
+ S.Diag(FI->getLocation(), diag::note_nontrivial_objc_ownership)
+ << RD << FieldType.getObjCLifetime();
+ return false;
+ }
+
+ if (ConstArg && !FI->isMutable())
+ FieldType.addConst();
+ if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, CSM,
+ TSK_Field, Diagnose))
+ return false;
+ }
+
+ return true;
+}
+
+/// Diagnose why the specified class does not have a trivial special member of
+/// the given kind.
+void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) {
+ QualType Ty = Context.getRecordType(RD);
+ if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)
+ Ty.addConst();
+
+ checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, CSM,
+ TSK_CompleteObject, /*Diagnose*/true);
+}
+
+/// Determine whether a defaulted or deleted special member function is trivial,
+/// as specified in C++11 [class.ctor]p5, C++11 [class.copy]p12,
+/// C++11 [class.copy]p25, and C++11 [class.dtor]p5.
+bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose) {
+ // Note that we can't work out CSM for ourselves. Consider this:
+ //
+ // struct S { S(int); S(const S&=0) = delete; };
+ //
+ // The same function is a trivial copy constructor but a non-trivial default
+ // constructor.
+ assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough");
+
+ CXXRecordDecl *RD = MD->getParent();
+
+ bool ConstArg = false;
+ ParmVarDecl *Param0 = MD->getNumParams() ? MD->getParamDecl(0) : 0;
+
+ // C++11 [class.copy]p12, p25:
+ // A [special member] is trivial if its declared parameter type is the same
+ // as if it had been implicitly declared [...]
+ switch (CSM) {
+ case CXXDefaultConstructor:
+ case CXXDestructor:
+ // Trivial default constructors and destructors cannot have parameters.
+ break;
+
+ case CXXCopyConstructor:
+ case CXXCopyAssignment: {
+ // Trivial copy operations always have const, non-volatile parameter types.
+ ConstArg = true;
+ const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
+ if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
+ if (Diagnose)
+ Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
+ << Param0->getSourceRange() << Param0->getType()
+ << Context.getLValueReferenceType(
+ Context.getRecordType(RD).withConst());
+ return false;
+ }
+ break;
+ }
+
+ case CXXMoveConstructor:
+ case CXXMoveAssignment: {
+ // Trivial move operations always have non-cv-qualified parameters.
+ const RValueReferenceType *RT =
+ Param0->getType()->getAs<RValueReferenceType>();
+ if (!RT || RT->getPointeeType().getCVRQualifiers()) {
+ if (Diagnose)
+ Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
+ << Param0->getSourceRange() << Param0->getType()
+ << Context.getRValueReferenceType(Context.getRecordType(RD));
+ return false;
+ }
+ break;
+ }
+
+ case CXXInvalid:
+ llvm_unreachable("not a special member");
+ }
+
+ // FIXME: We require that the parameter-declaration-clause is equivalent to
+ // that of an implicit declaration, not just that the declared parameter type
+ // matches, in order to prevent absuridities like a function simultaneously
+ // being a trivial copy constructor and a non-trivial default constructor.
+ // This issue has not yet been assigned a core issue number.
+ if (MD->getMinRequiredArguments() < MD->getNumParams()) {
+ if (Diagnose)
+ Diag(MD->getParamDecl(MD->getMinRequiredArguments())->getLocation(),
+ diag::note_nontrivial_default_arg)
+ << MD->getParamDecl(MD->getMinRequiredArguments())->getSourceRange();
+ return false;
+ }
+ if (MD->isVariadic()) {
+ if (Diagnose)
+ Diag(MD->getLocation(), diag::note_nontrivial_variadic);
+ return false;
+ }
+
+ // C++11 [class.ctor]p5, C++11 [class.dtor]p5:
+ // A copy/move [constructor or assignment operator] is trivial if
+ // -- the [member] selected to copy/move each direct base class subobject
+ // is trivial
+ //
+ // C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor or destructor] is trivial if
+ // -- all the direct base classes have trivial [default constructors or
+ // destructors]
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end(); BI != BE; ++BI)
+ if (!checkTrivialSubobjectCall(*this, BI->getLocStart(),
+ ConstArg ? BI->getType().withConst()
+ : BI->getType(),
+ CSM, TSK_BaseClass, Diagnose))
+ return false;
+
+ // C++11 [class.ctor]p5, C++11 [class.dtor]p5:
+ // A copy/move [constructor or assignment operator] for a class X is
+ // trivial if
+ // -- for each non-static data member of X that is of class type (or array
+ // thereof), the constructor selected to copy/move that member is
+ // trivial
+ //
+ // C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor or destructor] is trivial if
+ // -- for all of the non-static data members of its class that are of class
+ // type (or array thereof), each such class has a trivial [default
+ // constructor or destructor]
+ if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, Diagnose))
+ return false;
+
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if [...]
+ // -- the destructor is not virtual
+ if (CSM == CXXDestructor && MD->isVirtual()) {
+ if (Diagnose)
+ Diag(MD->getLocation(), diag::note_nontrivial_virtual_dtor) << RD;
+ return false;
+ }
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [special member] for class X is trivial if [...]
+ // -- class X has no virtual functions and no virtual base classes
+ if (CSM != CXXDestructor && MD->getParent()->isDynamicClass()) {
+ if (!Diagnose)
+ return false;
+
+ if (RD->getNumVBases()) {
+ // Check for virtual bases. We already know that the corresponding
+ // member in all bases is trivial, so vbases must all be direct.
+ CXXBaseSpecifier &BS = *RD->vbases_begin();
+ assert(BS.isVirtual());
+ Diag(BS.getLocStart(), diag::note_nontrivial_has_virtual) << RD << 1;
+ return false;
+ }
+
+ // Must have a virtual method.
+ for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
+ ME = RD->method_end(); MI != ME; ++MI) {
+ if (MI->isVirtual()) {
+ SourceLocation MLoc = MI->getLocStart();
+ Diag(MLoc, diag::note_nontrivial_has_virtual) << RD << 0;
+ return false;
+ }
+ }
+
+ llvm_unreachable("dynamic class with no vbases and no virtual functions");
+ }
+
+ // Looks like it's trivial!
+ return true;
+}
+
/// \brief Data used with FindHiddenVirtualMethod
namespace {
struct FindHiddenVirtualMethodData {
@@ -7113,7 +7477,46 @@
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
if (!ClassDecl->isDependentType())
- CheckExplicitlyDefaultedMethods(ClassDecl);
+ CheckExplicitlyDefaultedAndDeletedMethods(ClassDecl);
+
+ // C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member
+ // function that is not a constructor declares that member function to be
+ // const. [...] The class of which that function is a member shall be
+ // a literal type.
+ //
+ // If the class has virtual bases, any constexpr members will already have
+ // been diagnosed by the checks performed on the member declaration, so
+ // suppress this (less useful) diagnostic.
+ //
+ // We delay this until we know whether an explicitly-defaulted (or deleted)
+ // destructor for the class is trivial.
+ if (LangOpts.CPlusPlus0x && !ClassDecl->isDependentType() &&
+ !ClassDecl->isLiteral() && !ClassDecl->getNumVBases()) {
+ for (CXXRecordDecl::method_iterator M = ClassDecl->method_begin(),
+ MEnd = ClassDecl->method_end();
+ M != MEnd; ++M) {
+ if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
+ switch (ClassDecl->getTemplateSpecializationKind()) {
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ // If a template instantiates to a non-literal type, but its members
+ // instantiate to constexpr functions, the template is technically
+ // ill-formed, but we allow it for sanity.
+ continue;
+
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ RequireLiteralType(M->getLocation(), Context.getRecordType(ClassDecl),
+ diag::err_constexpr_method_non_literal);
+ break;
+ }
+
+ // Only produce one error per class.
+ break;
+ }
+ }
+ }
}
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
@@ -10395,35 +10798,6 @@
// recovery.
}
Fn->setDeletedAsWritten();
-
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
- if (!MD)
- return;
-
- // A deleted special member function is trivial if the corresponding
- // implicitly-declared function would have been.
- switch (getSpecialMember(MD)) {
- case CXXInvalid:
- break;
- case CXXDefaultConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialDefaultConstructor());
- break;
- case CXXCopyConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialCopyConstructor());
- break;
- case CXXMoveConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialMoveConstructor());
- break;
- case CXXCopyAssignment:
- MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment());
- break;
- case CXXMoveAssignment:
- MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment());
- break;
- case CXXDestructor:
- MD->setTrivial(MD->getParent()->hasTrivialDestructor());
- break;
- }
}
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Dec 7 20:53:02 2012
@@ -3058,6 +3058,13 @@
//
// 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
// 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
+ //
+ // Note that these builtins do not behave as documented in g++: if a class
+ // has both a trivial and a non-trivial special member of a particular kind,
+ // they return false! For now, we emulate this behavior.
+ // FIXME: This appears to be a g++ bug: more complex cases reveal that it
+ // does not correctly compute triviality in the presence of multiple special
+ // members of the same kind. Revisit this once the g++ bug is fixed.
case UTT_HasTrivialDefaultConstructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If __is_pod (type) is true then the trait is true, else if type is
@@ -3065,9 +3072,9 @@
// constructor ([class.ctor]) then the trait is true, else it is false.
if (T.isPODType(Self.Context))
return true;
- if (const RecordType *RT =
- C.getBaseElementType(T)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDefaultConstructor();
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialDefaultConstructor() &&
+ !RD->hasNonTrivialDefaultConstructor();
return false;
case UTT_HasTrivialCopy:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3077,8 +3084,9 @@
// is true, else it is false.
if (T.isPODType(Self.Context) || T->isReferenceType())
return true;
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->hasTrivialCopyConstructor() &&
+ !RD->hasNonTrivialCopyConstructor();
return false;
case UTT_HasTrivialAssign:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3093,12 +3101,13 @@
// errors if the copy assignment operator is actually used, q.v.
// [class.copy]p12).
- if (C.getBaseElementType(T).isConstQualified())
+ if (T.isConstQualified())
return false;
if (T.isPODType(Self.Context))
return true;
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->hasTrivialCopyAssignment() &&
+ !RD->hasNonTrivialCopyAssignment();
return false;
case UTT_HasTrivialDestructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3115,9 +3124,8 @@
T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
return true;
- if (const RecordType *RT =
- C.getBaseElementType(T)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialDestructor();
return false;
// TODO: Propagate nothrowness for implicitly declared special members.
case UTT_HasNothrowAssign:
@@ -3134,9 +3142,8 @@
return false;
if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
return true;
- if (const RecordType *RT = T->getAs<RecordType>()) {
- CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyAssignment())
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
+ if (RD->hasTrivialCopyAssignment() && !RD->hasNonTrivialCopyAssignment())
return true;
bool FoundAssign = false;
@@ -3175,9 +3182,9 @@
// false.
if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
return true;
- if (const RecordType *RT = T->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyConstructor())
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
+ if (RD->hasTrivialCopyConstructor() &&
+ !RD->hasNonTrivialCopyConstructor())
return true;
bool FoundConstructor = false;
@@ -3216,9 +3223,9 @@
// throw an exception then the trait is true, else it is false.
if (T.isPODType(C) || T->isObjCLifetimeType())
return true;
- if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDefaultConstructor())
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
+ if (RD->hasTrivialDefaultConstructor() &&
+ !RD->hasNonTrivialDefaultConstructor())
return true;
DeclContext::lookup_const_iterator Con, ConEnd;
@@ -3245,11 +3252,9 @@
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If type is a class type with a virtual destructor ([class.dtor])
// then the trait is true, else it is false.
- if (const RecordType *Record = T->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD))
return Destructor->isVirtual();
- }
return false;
// These type trait expressions are modeled on the specifications for the
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Dec 7 20:53:02 2012
@@ -1581,10 +1581,10 @@
SemaRef.CheckOverrideControl(Method);
// If a function is defined as defaulted or deleted, mark it as such now.
- if (D->isDefaulted())
- Method->setDefaulted();
+ if (D->isExplicitlyDefaulted())
+ SemaRef.SetDeclDefaulted(Method, Method->getLocation());
if (D->isDeletedAsWritten())
- Method->setDeletedAsWritten();
+ SemaRef.SetDeclDeleted(Method, Method->getLocation());
// If there's a function template, let our caller handle it.
if (FunctionTemplate) {
@@ -1610,13 +1610,6 @@
Owner->addDecl(Method);
}
- if (D->isExplicitlyDefaulted()) {
- SemaRef.SetDeclDefaulted(Method, Method->getLocation());
- } else {
- assert(!D->isDefaulted() &&
- "should not implicitly default uninstantiated function");
- }
-
return Method;
}
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Dec 7 20:53:02 2012
@@ -4564,6 +4564,8 @@
Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
diag::note_non_literal_user_provided_dtor :
diag::note_non_literal_nontrivial_dtor) << RD;
+ if (!Dtor->isUserProvided())
+ SpecialMemberIsTrivial(Dtor, CXXDestructor, /*Diagnose*/true);
}
return true;
Modified: cfe/trunk/test/CXX/basic/basic.types/p10.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.types/p10.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.types/p10.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.types/p10.cpp Fri Dec 7 20:53:02 2012
@@ -39,7 +39,7 @@
struct NonTrivDtor {
constexpr NonTrivDtor();
constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
- virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
+ virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} expected-note {{because it is virtual}}
};
struct NonTrivDtorBase {
~NonTrivDtorBase();
Modified: cfe/trunk/test/CXX/class/class.union/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.union/p1.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.union/p1.cpp (original)
+++ cfe/trunk/test/CXX/class/class.union/p1.cpp Fri Dec 7 20:53:02 2012
@@ -14,25 +14,25 @@
};
class Ctor {
- Ctor() { abort(); } // expected-note 4 {{because type 'Ctor' has a user-declared constructor}}
+ Ctor() { abort(); } // expected-note 2{{because type 'Ctor' has a user-provided default constructor}} expected-note 2{{here}}
};
class Ctor2 {
- Ctor2(); // expected-note 3 {{because type 'Ctor2' has a user-declared constructor}}
+ Ctor2(); // expected-note {{because type 'Ctor2' has a user-provided default constructor}} expected-note 2{{here}}
};
-class CtorTmpl {
- template<typename T> CtorTmpl(); // expected-note {{because type 'CtorTmpl' has a user-declared constructor}}
+class CtorTmpl { // expected-note {{because type 'CtorTmpl' has no default constructor}}
+ template<typename T> CtorTmpl(); // expected-note {{implicit default constructor suppressed by user-declared constructor}}
};
-class CopyCtor {
- CopyCtor(CopyCtor &cc) { abort(); } // expected-note 4 {{because type 'CopyCtor' has a user-declared copy constructor}}
+class CopyCtor { // expected-note 2{{because no constructor can be used to copy an object of type 'const CopyCtor'}}
+ CopyCtor(CopyCtor &cc) { abort(); }
};
-class CopyAssign {
- CopyAssign& operator=(CopyAssign& CA) { abort(); } // expected-note 4 {{because type 'CopyAssign' has a user-declared copy assignment operator}}
+class CopyAssign { // expected-note 2 {{because no assignment operator can be used to copy an object of type 'const CopyAssign'}}
+ CopyAssign& operator=(CopyAssign& CA) { abort(); }
};
class Dtor {
- ~Dtor() { abort(); } // expected-note 4 {{because type 'Dtor' has a user-declared destructor}}
+ ~Dtor() { abort(); } // expected-note 2 {{because type 'Dtor' has a user-provided destructor}} expected-note 2{{here}}
};
union U1 {
@@ -49,25 +49,25 @@
union U2 {
struct {
- Virtual v; // expected-note {{because type 'U2::<anonymous struct}}
+ Virtual v; // expected-note {{because the function selected to copy field of type 'Virtual' is not trivial}}
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
struct {
- VirtualBase vbase; // expected-note {{because type 'U2::<anonymous struct}}
+ VirtualBase vbase; // expected-note {{because the function selected to copy field of type 'VirtualBase' is not trivial}}
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
struct {
- Ctor ctor; // expected-note {{because type 'U2::<anonymous struct}}
+ Ctor ctor; // expected-note {{because field of type 'Ctor' has a user-provided default constructor}}
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
struct {
- Ctor2 ctor2; // expected-note {{because type 'U2::<anonymous struct}}
+ Ctor2 ctor2; // expected-note {{because field of type 'Ctor2' has a user-provided default constructor}}
} m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}}
- struct {
- CopyCtor copyctor; // expected-note {{because type 'U2::<anonymous struct}}
+ struct { // expected-note {{no constructor can be used to copy an object of type 'const}}
+ CopyCtor copyctor;
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
- struct {
- CopyAssign copyassign; // expected-note {{because type 'U2::<anonymous struct}}
+ struct { // expected-note {{no assignment operator can be used to copy an object of type 'const}}
+ CopyAssign copyassign;
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
struct {
- Dtor dtor; // expected-note {{because type 'U2::<anonymous struct}}
+ Dtor dtor; // expected-note {{because field of type 'Dtor' has a user-provided destructor}}
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
struct {
Okay okay;
@@ -75,22 +75,25 @@
};
union U3 {
- struct s1 : Virtual { // expected-note {{because type 'U3::s1' has a base class with a non-trivial copy constructor}}
+ struct s1 : Virtual { // expected-note {{because the function selected to copy base class of type 'Virtual' is not trivial}}
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
- struct s2 : VirtualBase { // expected-note {{because type 'U3::s2' has a base class with a non-trivial copy constructor}}
+ struct s2 : VirtualBase { // expected-note {{because the function selected to copy base class of type 'VirtualBase' is not trivial}}
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
- struct s3 : Ctor { // expected-note {{because type 'U3::s3' has a base class with a non-trivial constructor}}
+ struct s3 : Ctor { // expected-note {{because base class of type 'Ctor' has a user-provided default constructor}}
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
- struct s3a : Ctor2 { // expected-note {{because type 'U3::s3a' has a base class with a non-trivial constructor}}
+ struct s3a : Ctor2 { // expected-note {{because base class of type 'Ctor2' has a user-provided default constructor}}
} m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}}
- struct s4 : CopyCtor { // expected-note {{because type 'U3::s4' has a base class with a non-trivial copy constructor}}
+ struct s4 : CopyCtor { // expected-note {{because no constructor can be used to copy an object of type 'const U3::s4'}}
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
- struct s5 : CopyAssign { // expected-note {{because type 'U3::s5' has a base class with a non-trivial copy assignment operator}}
+ struct s5 : CopyAssign { // expected-note {{because no assignment operator can be used to copy an object of type 'const U3::s5'}}
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
- struct s6 : Dtor { // expected-note {{because type 'U3::s6' has a base class with a non-trivial destructor}}
+ struct s6 : Dtor { // expected-note {{because base class of type 'Dtor' has a user-provided destructor}}
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
struct s7 : Okay {
} m7;
+ struct s8 {
+ s8(...) = delete; // expected-note {{because it is a variadic function}} expected-warning {{C++11}}
+ } m8; // expected-error {{union member 'm8' has a non-trivial constructor}}
};
union U4 {
Modified: cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp Fri Dec 7 20:53:02 2012
@@ -14,11 +14,10 @@
// (except for possibly differing ref-qualifiers
A &operator=(A &&) & = default;
- // FIXME:
// and except that in the case of a copy constructor or copy assignment
// operator, the parameter type may be "reference to non-const T")
- A(A &) = default; // FIXME: expected-error {{must be defaulted outside the class}}
- A &operator=(A &) = default; // FIXME: expected-error {{must be defaulted outside the class}}
+ A(A &) = default;
+ A &operator=(A &) = default;
// -- not have default arguments
A(double = 0.0) = default; // expected-error {{cannot have default arguments}}
Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp Fri Dec 7 20:53:02 2012
@@ -38,8 +38,8 @@
};
struct NonConst {
- NonConst(NonConst&) = default; // expected-error {{must be defaulted outside the class}}
- NonConst& operator=(NonConst&) = default; // expected-error {{must be defaulted outside the class}}
+ NonConst(NonConst&) = default;
+ NonConst& operator=(NonConst&) = default;
};
struct NonConst2 {
Added: cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp?rev=169667&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp (added)
+++ cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp Fri Dec 7 20:53:02 2012
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename T, bool B> struct trivially_copyable_check {
+ static_assert(B == __has_trivial_copy(T), "");
+ static_assert(B == __is_trivially_constructible(T, T), "");
+ static_assert(B == __is_trivially_constructible(T, const T &), "");
+ static_assert(B == __is_trivially_constructible(T, T &&), "");
+ typedef void type;
+};
+template<typename T> using trivially_copyable =
+ typename trivially_copyable_check<T, true>::type;
+template<typename T> using not_trivially_copyable =
+ typename trivially_copyable_check<T, false>::type;
+
+struct Trivial {};
+using _ = trivially_copyable<Trivial>;
+
+// A copy/move constructor for class X is trivial if it is not user-provided,
+struct UserProvided {
+ UserProvided(const UserProvided &);
+};
+using _ = not_trivially_copyable<UserProvided>;
+
+// its declared parameter type is the same as if it had been implicitly
+// declared,
+struct NonConstCopy {
+ NonConstCopy(NonConstCopy &) = default;
+};
+using _ = not_trivially_copyable<NonConstCopy>;
+
+// class X has no virtual functions
+struct VFn {
+ virtual void f();
+};
+using _ = not_trivially_copyable<VFn>;
+
+// and no virtual base classes
+struct VBase : virtual Trivial {};
+using _ = not_trivially_copyable<VBase>;
+
+// and the constructor selected to copy/move each [direct subobject] is trivial
+struct TemplateCtor {
+ template<typename T> TemplateCtor(T &);
+};
+using _ = trivially_copyable<TemplateCtor>;
+struct TemplateCtorMember {
+ TemplateCtor tc;
+};
+using _ = trivially_copyable<TemplateCtorMember>;
+
+// We can select a non-trivial copy ctor even if there is a trivial one.
+struct MutableTemplateCtorMember {
+ mutable TemplateCtor mtc;
+};
+// FIXME: This is wrong! The "trivial" copy constructor calls the templated
+// constructor for the mutable member.
+static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); // expected-error {{}}
+static_assert(__is_trivially_constructible(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
+struct MutableTemplateCtorMember2 {
+ MutableTemplateCtorMember2(const MutableTemplateCtorMember2 &) = default;
+ MutableTemplateCtorMember2(MutableTemplateCtorMember2 &&) = default;
+ mutable TemplateCtor mtc;
+};
+static_assert(!__is_trivially_constructible(MutableTemplateCtorMember2, const MutableTemplateCtorMember2 &), "");
+static_assert(__is_trivially_constructible(MutableTemplateCtorMember2, MutableTemplateCtorMember2 &&), "");
+
+// Both trivial and non-trivial special members.
+struct TNT {
+ TNT(const TNT &) = default; // trivial
+ TNT(TNT &); // non-trivial
+
+ TNT(TNT &&) = default; // trivial
+ TNT(const TNT &&); // non-trivial
+};
+
+static_assert(!__has_trivial_copy(TNT), "lie deliberately for gcc compatibility");
+static_assert(__is_trivially_constructible(TNT, TNT), "");
+static_assert(!__is_trivially_constructible(TNT, TNT &), "");
+static_assert(__is_trivially_constructible(TNT, const TNT &), "");
+static_assert(!__is_trivially_constructible(TNT, volatile TNT &), "");
+static_assert(__is_trivially_constructible(TNT, TNT &&), "");
+static_assert(!__is_trivially_constructible(TNT, const TNT &&), "");
+static_assert(!__is_trivially_constructible(TNT, volatile TNT &&), "");
+
+// This has only trivial special members.
+struct DerivedFromTNT : TNT {};
+
+static_assert(__has_trivial_copy(DerivedFromTNT), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &), "");
+static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &&), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &&), "");
+static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &&), "");
+
+// This has only trivial special members.
+struct TNTMember {
+ TNT tnt;
+};
+
+static_assert(__has_trivial_copy(TNTMember), "");
+static_assert(__is_trivially_constructible(TNTMember, TNTMember), "");
+static_assert(__is_trivially_constructible(TNTMember, TNTMember &), "");
+static_assert(__is_trivially_constructible(TNTMember, const TNTMember &), "");
+static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &), "");
+static_assert(__is_trivially_constructible(TNTMember, TNTMember &&), "");
+static_assert(__is_trivially_constructible(TNTMember, const TNTMember &&), "");
+static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &&), "");
+
+struct NCCTNT : NonConstCopy, TNT {};
+
+static_assert(!__has_trivial_copy(NCCTNT), "");
+static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT), "");
+static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &), "");
+static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &), "");
+static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &), "");
+static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &&), "");
+static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &&), "");
+static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &&), "");
Added: cfe/trunk/test/CXX/special/class.copy/p25-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p25-0x.cpp?rev=169667&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p25-0x.cpp (added)
+++ cfe/trunk/test/CXX/special/class.copy/p25-0x.cpp Fri Dec 7 20:53:02 2012
@@ -0,0 +1,143 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename T, bool B> struct trivially_assignable_check {
+ static_assert(B == __has_trivial_assign(T), "");
+ static_assert(B == __is_trivially_assignable(T&, T), "");
+ static_assert(B == __is_trivially_assignable(T&, const T &), "");
+ static_assert(B == __is_trivially_assignable(T&, T &&), "");
+ static_assert(B == __is_trivially_assignable(T&&, T), "");
+ static_assert(B == __is_trivially_assignable(T&&, const T &), "");
+ static_assert(B == __is_trivially_assignable(T&&, T &&), "");
+ typedef void type;
+};
+template<typename T> using trivially_assignable =
+ typename trivially_assignable_check<T, true>::type;
+template<typename T> using not_trivially_assignable =
+ typename trivially_assignable_check<T, false>::type;
+
+struct Trivial {};
+using _ = trivially_assignable<Trivial>;
+
+// A copy/move assignment operator for class X is trivial if it is not user-provided,
+struct UserProvided {
+ UserProvided &operator=(const UserProvided &);
+};
+using _ = not_trivially_assignable<UserProvided>;
+
+// its declared parameter type is the same as if it had been implicitly
+// declared,
+struct NonConstCopy {
+ NonConstCopy &operator=(NonConstCopy &) = default;
+};
+using _ = not_trivially_assignable<NonConstCopy>;
+
+// class X has no virtual functions
+struct VFn {
+ virtual void f();
+};
+using _ = not_trivially_assignable<VFn>;
+
+// and no virtual base classes
+struct VBase : virtual Trivial {};
+using _ = not_trivially_assignable<VBase>;
+
+// and the assignment operator selected to copy/move each [direct subobject] is trivial
+struct TemplateCtor {
+ template<typename T> TemplateCtor operator=(T &);
+};
+using _ = trivially_assignable<TemplateCtor>;
+struct TemplateCtorMember {
+ TemplateCtor tc;
+};
+using _ = trivially_assignable<TemplateCtorMember>;
+struct MutableTemplateCtorMember {
+ mutable TemplateCtor mtc;
+};
+// FIXME: This is wrong! The "trivial" copy constructor calls the templated
+// constructor for the mutable member.
+static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); // expected-error {{}}
+static_assert(__is_trivially_assignable(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
+
+// Both trivial and non-trivial special members.
+struct TNT {
+ TNT &operator=(const TNT &) = default; // trivial
+ TNT &operator=(TNT &); // non-trivial
+
+ TNT &operator=(TNT &&) = default; // trivial
+ TNT &operator=(const TNT &&); // non-trivial
+};
+
+static_assert(!__has_trivial_assign(TNT), "lie deliberately for gcc compatibility");
+static_assert(__is_trivially_assignable(TNT, TNT), "");
+static_assert(!__is_trivially_assignable(TNT, TNT &), "");
+static_assert(__is_trivially_assignable(TNT, const TNT &), "");
+static_assert(!__is_trivially_assignable(TNT, volatile TNT &), "");
+static_assert(__is_trivially_assignable(TNT, TNT &&), "");
+static_assert(!__is_trivially_assignable(TNT, const TNT &&), "");
+static_assert(!__is_trivially_assignable(TNT, volatile TNT &&), "");
+
+// This has only trivial special members.
+struct DerivedFromTNT : TNT {};
+
+static_assert(__has_trivial_assign(DerivedFromTNT), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &), "");
+static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &&), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &&), "");
+static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &&), "");
+
+// This has only trivial special members.
+struct TNTMember {
+ TNT tnt;
+};
+
+static_assert(__has_trivial_assign(TNTMember), "");
+static_assert(__is_trivially_assignable(TNTMember, TNTMember), "");
+static_assert(__is_trivially_assignable(TNTMember, TNTMember &), "");
+static_assert(__is_trivially_assignable(TNTMember, const TNTMember &), "");
+static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &), "");
+static_assert(__is_trivially_assignable(TNTMember, TNTMember &&), "");
+static_assert(__is_trivially_assignable(TNTMember, const TNTMember &&), "");
+static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &&), "");
+
+struct NCCTNT : NonConstCopy, TNT {};
+
+static_assert(!__has_trivial_assign(NCCTNT), "");
+static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT), "");
+static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &), "");
+static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &), "");
+static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &), "");
+static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &&), "");
+static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &&), "");
+static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &&), "");
+
+struct MultipleTrivial {
+ // All four of these are trivial.
+ MultipleTrivial &operator=(const MultipleTrivial &) & = default;
+ MultipleTrivial &operator=(const MultipleTrivial &) && = default;
+ MultipleTrivial &operator=(MultipleTrivial &&) & = default;
+ MultipleTrivial &operator=(MultipleTrivial &&) && = default;
+};
+
+using _ = trivially_assignable<MultipleTrivial>;
+
+struct RefQualifier {
+ RefQualifier &operator=(const RefQualifier &) & = default;
+ RefQualifier &operator=(const RefQualifier &) &&;
+ RefQualifier &operator=(RefQualifier &&) &;
+ RefQualifier &operator=(RefQualifier &&) && = default;
+};
+struct DerivedFromRefQualifier : RefQualifier {
+ // Both of these call the trivial copy operation.
+ DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) & = default;
+ DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) && = default;
+ // Both of these call the non-trivial move operation.
+ DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) & = default;
+ DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) && = default;
+};
+static_assert(__is_trivially_assignable(DerivedFromRefQualifier&, const DerivedFromRefQualifier&), "");
+static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), "");
+static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), "");
+static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), "");
Modified: cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp Fri Dec 7 20:53:02 2012
@@ -149,26 +149,41 @@
class NonTrivialDefCtor1 { NonTrivialDefCtor1(); };
static_assert(!__has_trivial_constructor(NonTrivialDefCtor1), "NonTrivialDefCtor1 is trivial");
+#define ASSERT_NONTRIVIAL_IMPL(Class, Bases, Body) \
+ class Class Bases { Body }; \
+ static_assert(!__has_trivial_constructor(Class), "");
+#define ASSERT_NONTRIVIAL(Class, Bases, Body) \
+ ASSERT_NONTRIVIAL_IMPL(Class, Bases, Body) \
+ ASSERT_NONTRIVIAL_IMPL(Def ## Class, Bases, Def ## Class() = default; Body) \
+ ASSERT_NONTRIVIAL_IMPL(Del ## Class, Bases, Del ## Class() = delete; Body)
+
// - its class has no virtual functions (10.3) and no virtual base classes (10.1), and
-class NonTrivialDefCtor2 { virtual void f(); };
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor2), "NonTrivialDefCtor2 is trivial");
-class NonTrivialDefCtor3 : virtual Trivial {};
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor3), "NonTrivialDefCtor3 is trivial");
+ASSERT_NONTRIVIAL(NonTrivialDefCtor2, , virtual void f();)
+ASSERT_NONTRIVIAL(NonTrivialDefCtor3, : virtual Trivial, )
// - no non-static data member of its class has a brace-or-equal-initializer, and
-class NonTrivialDefCtor4 { int m = 52; };
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor4), "NonTrivialDefCtor4 is trivial");
+ASSERT_NONTRIVIAL(NonTrivialDefCtor4, , int m = 52;)
// - all the direct base classes of its class have trivial default constructors, and
-class NonTrivialDefCtor5 : NonTrivialDefCtor1 {};
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor5), "NonTrivialDefCtor5 is trivial");
+ASSERT_NONTRIVIAL(NonTrivialDefCtor5, : NonTrivialDefCtor1, )
// - for all the non-static data members of its class that are of class type (or array thereof), each such class
// has a trivial default constructor.
-class NonTrivialDefCtor6 { NonTrivialDefCtor1 t; };
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor5 is trivial");
+ASSERT_NONTRIVIAL(NonTrivialDefCtor6, , NonTrivialDefCtor1 t;)
+
+// FIXME: No core issue number yet.
+// - its parameter-declaration-clause is equivalent to that of an implicit declaration.
+struct NonTrivialDefCtor7 {
+ NonTrivialDefCtor7(...) = delete;
+};
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor7), "");
+struct NonTrivialDefCtor8 {
+ NonTrivialDefCtor8(int = 0) = delete;
+};
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor8), "");
// Otherwise, the default constructor is non-trivial.
+
class Trivial2 { Trivial2() = delete; };
static_assert(__has_trivial_constructor(Trivial2), "Trivial2 is trivial");
Modified: cfe/trunk/test/SemaCXX/anonymous-struct.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/anonymous-struct.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/anonymous-struct.cpp (original)
+++ cfe/trunk/test/SemaCXX/anonymous-struct.cpp Fri Dec 7 20:53:02 2012
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct S {
- S(); // expected-note {{because type 'S' has a user-declared constructor}}
+ S(); // expected-note {{because type 'S' has a user-provided default constructor}}
};
struct { // expected-error {{anonymous structs and classes must be class members}}
@@ -9,7 +9,7 @@
struct E {
struct {
- S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}}
+ S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}}
};
static struct {
};
Modified: cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp Fri Dec 7 20:53:02 2012
@@ -36,9 +36,9 @@
};
struct bad_decls {
- bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}} expected-error {{must be defaulted outside the class}}
+ bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}}
bad_decls&& operator = (bad_decls) = default; // expected-error {{lvalue reference}} expected-error {{must return 'bad_decls &'}}
- bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}} expected-error {{must be defaulted outside the class}}
+ bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}}
bad_decls& operator = (const bad_decls&) const = default; // expected-error {{may not have 'const', 'constexpr' or 'volatile' qualifiers}}
};
@@ -57,14 +57,18 @@
~except_spec_d_good();
};
except_spec_d_good::~except_spec_d_good() = default;
-// FIXME: This should error in the virtual override check.
-// It doesn't because we generate the implicit specification later than
-// appropriate.
+struct except_spec_d_good2 : except_spec_a, except_spec_b {
+ ~except_spec_d_good2() = default;
+};
struct except_spec_d_bad : except_spec_a, except_spec_b {
- ~except_spec_d_bad() = default;
+ ~except_spec_d_bad() noexcept;
};
+// FIXME: This should error because this exception spec is not
+// compatible with the implicit exception spec.
+except_spec_d_bad::~except_spec_d_bad() noexcept = default;
-// FIXME: This should error because the exceptions spec doesn't match.
+// FIXME: This should error because this exception spec is not
+// compatible with the implicit exception spec.
struct except_spec_d_mismatch : except_spec_a, except_spec_b {
except_spec_d_mismatch() throw(A) = default;
};
Modified: cfe/trunk/test/SemaCXX/cxx98-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx98-compat.cpp?rev=169667&r1=169666&r2=169667&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx98-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx98-compat.cpp Fri Dec 7 20:53:02 2012
@@ -254,13 +254,13 @@
namespace UnionOrAnonStructMembers {
struct NonTrivCtor {
- NonTrivCtor(); // expected-note 2{{user-declared constructor}}
+ NonTrivCtor(); // expected-note 2{{user-provided default constructor}}
};
struct NonTrivCopy {
- NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-declared copy constructor}}
+ NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-provided copy constructor}}
};
struct NonTrivDtor {
- ~NonTrivDtor(); // expected-note 2{{user-declared destructor}}
+ ~NonTrivDtor(); // expected-note 2{{user-provided destructor}}
};
union BadUnion {
NonTrivCtor ntc; // expected-warning {{union member 'ntc' with a non-trivial constructor is incompatible with C++98}}
@@ -338,8 +338,8 @@
namespace PR13480 {
struct basic_iterator {
- basic_iterator(const basic_iterator &it) {}
- basic_iterator(basic_iterator &it) {} // expected-note {{because type 'PR13480::basic_iterator' has a user-declared copy constructor}}
+ basic_iterator(const basic_iterator &it) {} // expected-note {{because type 'PR13480::basic_iterator' has a user-provided copy constructor}}
+ basic_iterator(basic_iterator &it) {}
};
union test {
@@ -349,12 +349,12 @@
namespace AssignOpUnion {
struct a {
- void operator=(const a &it) {}
- void operator=(a &it) {} // expected-note {{because type 'AssignOpUnion::a' has a user-declared copy assignment operator}}
+ void operator=(const a &it) {} // expected-note {{because type 'AssignOpUnion::a' has a user-provided copy assignment operator}}
+ void operator=(a &it) {}
};
struct b {
- void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-declared copy assignment operator}}
+ void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-provided copy assignment operator}}
};
union test1 {
@@ -364,9 +364,9 @@
}
namespace rdar11736429 {
- struct X {
+ struct X { // expected-note {{because type 'rdar11736429::X' has no default constructor}}
X(const X&) = delete; // expected-warning{{deleted function definitions are incompatible with C++98}} \
- // expected-note{{because type 'rdar11736429::X' has a user-declared constructor}}
+ // expected-note {{implicit default constructor suppressed by user-declared constructor}}
};
union S {
More information about the cfe-commits
mailing list