[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