<div dir="ltr">Thanks for a quick response, "#include <string>" indeed helped.</div><br><div class="gmail_quote"><div dir="ltr">On Thu, Aug 17, 2017 at 5:41 PM Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 17 August 2017 at 17:28, Petr Hosek via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">We're seeing a build failure in WebKit which appears to be have been introduced by this change:<div><br></div><div><div>../../buildtools/linux-x64/clang/bin/clang++ -MD -MF obj/apps/web_view/web_view_test.test_webview.o.d -DTOOLCHAIN_VERSION=4e89c701396412a50a901115ab4a2a09145f3777 -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DCAIRO_HAS_FC_FONT=0 -DU_USING_ICU_NAMESPACE=0 -DU_ENABLE_DYLOAD=0 -DU_STATIC_IMPLEMENTATION -DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE -I../.. -Igen -I../../third_party/webkit/Source/WebKit/fuchsia -I../../third_party/boringssl/include -Igen/third_party/cairo -I../../third_party/curl/include -Iobj/third_party/curl -Iobj/third_party/curl/curl -I../../third_party/freetype2/include -I../../third_party/harfbuzz/src -I../../third_party/icu/source/common -I../../third_party/icu/source/i18n -I../../third_party/libjpeg-turbo -I../../third_party/libpng -I../../third_party/zlib -I../../third_party/libxml2/include -I../../third_party/sqlite -g --sysroot=/usr/local/google/home/phosek/fuchsia/out/build-magenta/build-magenta-pc-x86-64/sysroot --target=x86_64-fuchsia -no-canonical-prefixes -fdebug-prefix-map=/usr/local/google/home/phosek/fuchsia=. -Wall -Wextra -Wno-unused-parameter -Wno-enum-compare-switch -Wno-unused-lambda-capture -Wno-user-defined-warnings -fvisibility=hidden -g -Og -fsanitize=safe-stack -fstack-protector-strong -Werror -Wno-error=deprecated-declarations -fvisibility-inlines-hidden -std=c++14 -fno-exceptions -fno-rtti -Wthread-safety -c ../../apps/web_view/test_webview.cpp -o obj/apps/web_view/web_view_test.test_webview.o</div><div>In file included from ../../apps/web_view/test_webview.cpp:1:</div><div>In file included from ../../third_party/webkit/Source/WebKit/fuchsia/WebView.h:28:</div><div>In file included from ../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/functional:484:</div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/type_traits:4323:23: error: implicit instantiation of undefined template 'std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> >'</div><div>_LIBCPP_INVOKE_RETURN(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...))</div><div>                      ^</div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/__config:468:15: note: expanded from macro '_VSTD'</div><div>#define _VSTD std::_LIBCPP_NAMESPACE</div><div>              ^</div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/type_traits:4340:9: note: in instantiation of exception specification for '__invoke<std::__2::function<std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > (const std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > &)> &, const std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > &>' requested here</div><div>        _VSTD::__invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...));</div><div>        ^</div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/__config:468:15: note: expanded from macro '_VSTD'</div><div>#define _VSTD std::_LIBCPP_NAMESPACE</div><div>              ^</div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/functional:1601:33: note: in instantiation of template class 'std::__2::__invokable_r<void, std::__2::function<std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > (const std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > &)> &, const std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > &>' requested here</div><div>                                __invokable<_Fp&, _ArgTypes...>::value></div><div>                                ^</div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/functional:1626:9: note: in instantiation of default argument for '__callable<std::__2::function<std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > (const std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > &)> >' required here</div><div>        __callable<_Fp>::value && !is_same<_Fp, function>::value</div><div>        ^~~~~~~~~~~~~~~</div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/functional:1628:5: note: in instantiation of default argument for 'function<std::__2::function<std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > (const std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > &)> >' required here</div><div>    function(_Fp);</div><div>    ^~~~~~~~~~~~~</div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/functional:1588:28: note: while substituting deduced template arguments into function template 'function' [with _Fp = std::__2::function<std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > (const std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char> > &)>, $1 = (no value)]</div><div>class _LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes...)></div><div>                           ^</div><div>../../third_party/webkit/Source/WebKit/fuchsia/WebView.h:48:7: note: while declaring the implicit copy constructor for 'WebView'</div><div>class WebView {</div><div>      ^</div></div></div></blockquote><div><br></div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>It looks like WebView has a member of type std::function<std::string(const std::string&)>. When a compiler sees a class definition, it is permitted (or by a strict reading of the standard, required) to determine whether the implicit special member functions of that class should be deleted, which involves attempting to copy / move the members of that class. (This change slightly expands the set of conditions under which Clang will actually attempt this determination when it sees a class definition.)</div><div><br></div><div>In this case, attempting to copy a function<string(const string&)> appears to require 'string' to be a complete type, which it isn't, presumably because the relevant header fails to #include <string>. In short, it appears that this is a latent source code bug. You need to add "#include <string>" to WebView.h.</div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div>../../buildtools/linux-x64/clang/lib/x86_64-fuchsia/include/c++/v1/iosfwd:193:32: note: template is declared here</div><div>    class _LIBCPP_TEMPLATE_VIS basic_string;</div><div>                               ^</div><div>1 error generated.</div><div><div class="m_7715471667545254262h5"><br><div class="gmail_quote"><div dir="ltr">On Tue, Aug 15, 2017 at 6:50 PM Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Tue Aug 15 18:49:53 2017<br>
New Revision: 310983<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=310983&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=310983&view=rev</a><br>
Log:<br>
PR19668, PR23034: Fix handling of move constructors and deleted copy<br>
constructors when deciding whether classes should be passed indirectly.<br>
<br>
This fixes ABI differences between Clang and GCC:<br>
<br>
 * Previously, Clang ignored the move constructor when making this<br>
   determination. It now takes the move constructor into account, per<br>
   <a href="https://github.com/itanium-cxx-abi/cxx-abi/pull/17" rel="noreferrer" target="_blank">https://github.com/itanium-cxx-abi/cxx-abi/pull/17</a> (this change may<br>
   seem recent, but the ABI change was agreed on the Itanium C++ ABI<br>
   list a long time ago).<br>
<br>
 * Previously, Clang's behavior when the copy constructor was deleted<br>
   was unstable -- depending on whether the lazy declaration of the<br>
   copy constructor had been triggered, you might get different behavior.<br>
   We now eagerly declare the copy constructor whenever its deletedness<br>
   is unclear, and ignore deleted copy/move constructors when looking for<br>
   a trivial such constructor.<br>
<br>
This also fixes an ABI difference between Clang and MSVC:<br>
<br>
 * If the copy constructor would be implicitly deleted (but has not been<br>
   lazily declared yet), for instance because the class has an rvalue<br>
   reference member, we would pass it directly. We now pass such a class<br>
   indirectly, matching MSVC.<br>
<br>
Based on a patch by Vassil Vassilev, which was based on a patch by Bernd<br>
Schmidt, which was based on a patch by Reid Kleckner!<br>
<br>
This is a re-commit of r310401, which was reverted in r310464 due to ARM<br>
failures (which should now be fixed).<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/AST/DeclCXX.h<br>
    cfe/trunk/lib/AST/ASTImporter.cpp<br>
    cfe/trunk/lib/AST/DeclCXX.cpp<br>
    cfe/trunk/lib/CodeGen/CGCXXABI.cpp<br>
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp<br>
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp<br>
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp<br>
    cfe/trunk/lib/Serialization/ASTWriter.cpp<br>
    cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp<br>
    cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/DeclCXX.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)<br>
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Aug 15 18:49:53 2017<br>
@@ -374,6 +374,7 @@ class CXXRecordDecl : public RecordDecl<br>
     /// \brief These flags are \c true if a defaulted corresponding special<br>
     /// member can't be fully analyzed without performing overload resolution.<br>
     /// @{<br>
+    unsigned NeedOverloadResolutionForCopyConstructor : 1;<br>
     unsigned NeedOverloadResolutionForMoveConstructor : 1;<br>
     unsigned NeedOverloadResolutionForMoveAssignment : 1;<br>
     unsigned NeedOverloadResolutionForDestructor : 1;<br>
@@ -382,6 +383,7 @@ class CXXRecordDecl : public RecordDecl<br>
     /// \brief These flags are \c true if an implicit defaulted corresponding<br>
     /// special member would be defined as deleted.<br>
     /// @{<br>
+    unsigned DefaultedCopyConstructorIsDeleted : 1;<br>
     unsigned DefaultedMoveConstructorIsDeleted : 1;<br>
     unsigned DefaultedMoveAssignmentIsDeleted : 1;<br>
     unsigned DefaultedDestructorIsDeleted : 1;<br>
@@ -414,6 +416,12 @@ class CXXRecordDecl : public RecordDecl<br>
     /// constructor.<br>
     unsigned HasDefaultedDefaultConstructor : 1;<br>
<br>
+    /// \brief True if this class can be passed in a non-address-preserving<br>
+    /// fashion (such as in registers) according to the C++ language rules.<br>
+    /// This does not imply anything about how the ABI in use will actually<br>
+    /// pass an object of this class.<br>
+    unsigned CanPassInRegisters : 1;<br>
+<br>
     /// \brief True if a defaulted default constructor for this class would<br>
     /// be constexpr.<br>
     unsigned DefaultedDefaultConstructorIsConstexpr : 1;<br>
@@ -810,18 +818,50 @@ public:<br>
     return data().FirstFriend.isValid();<br>
   }<br>
<br>
+  /// \brief \c true if a defaulted copy constructor for this class would be<br>
+  /// deleted.<br>
+  bool defaultedCopyConstructorIsDeleted() const {<br>
+    assert((!needsOverloadResolutionForCopyConstructor() ||<br>
+            (data().DeclaredSpecialMembers & SMF_CopyConstructor)) &&<br>
+           "this property has not yet been computed by Sema");<br>
+    return data().DefaultedCopyConstructorIsDeleted;<br>
+  }<br>
+<br>
+  /// \brief \c true if a defaulted move constructor for this class would be<br>
+  /// deleted.<br>
+  bool defaultedMoveConstructorIsDeleted() const {<br>
+    assert((!needsOverloadResolutionForMoveConstructor() ||<br>
+            (data().DeclaredSpecialMembers & SMF_MoveConstructor)) &&<br>
+           "this property has not yet been computed by Sema");<br>
+    return data().DefaultedMoveConstructorIsDeleted;<br>
+  }<br>
+<br>
+  /// \brief \c true if a defaulted destructor for this class would be deleted.<br>
+  bool defaultedDestructorIsDeleted() const {<br>
+    return !data().DefaultedDestructorIsDeleted;<br>
+  }<br>
+<br>
+  /// \brief \c true if we know for sure that this class has a single,<br>
+  /// accessible, unambiguous copy constructor that is not deleted.<br>
+  bool hasSimpleCopyConstructor() const {<br>
+    return !hasUserDeclaredCopyConstructor() &&<br>
+           !data().DefaultedCopyConstructorIsDeleted;<br>
+  }<br>
+<br>
   /// \brief \c true if we know for sure that this class has a single,<br>
   /// accessible, unambiguous move constructor that is not deleted.<br>
   bool hasSimpleMoveConstructor() const {<br>
     return !hasUserDeclaredMoveConstructor() && hasMoveConstructor() &&<br>
            !data().DefaultedMoveConstructorIsDeleted;<br>
   }<br>
+<br>
   /// \brief \c true if we know for sure that this class has a single,<br>
   /// accessible, unambiguous move assignment operator that is not deleted.<br>
   bool hasSimpleMoveAssignment() const {<br>
     return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&<br>
            !data().DefaultedMoveAssignmentIsDeleted;<br>
   }<br>
+<br>
   /// \brief \c true if we know for sure that this class has an accessible<br>
   /// destructor that is not deleted.<br>
   bool hasSimpleDestructor() const {<br>
@@ -877,7 +917,16 @@ public:<br>
   /// \brief Determine whether we need to eagerly declare a defaulted copy<br>
   /// constructor for this class.<br>
   bool needsOverloadResolutionForCopyConstructor() const {<br>
-    return data().HasMutableFields;<br>
+    // C++17 [class.copy.ctor]p6:<br>
+    //   If the class definition declares a move constructor or move assignment<br>
+    //   operator, the implicitly declared copy constructor is defined as<br>
+    //   deleted.<br>
+    // In MSVC mode, sometimes a declared move assignment does not delete an<br>
+    // implicit copy constructor, so defer this choice to Sema.<br>
+    if (data().UserDeclaredSpecialMembers &<br>
+        (SMF_MoveConstructor | SMF_MoveAssignment))<br>
+      return true;<br>
+    return data().NeedOverloadResolutionForCopyConstructor;<br>
   }<br>
<br>
   /// \brief Determine whether an implicit copy constructor for this type<br>
@@ -918,7 +967,16 @@ public:<br>
            needsImplicitMoveConstructor();<br>
   }<br>
<br>
-  /// \brief Set that we attempted to declare an implicitly move<br>
+  /// \brief Set that we attempted to declare an implicit copy<br>
+  /// constructor, but overload resolution failed so we deleted it.<br>
+  void setImplicitCopyConstructorIsDeleted() {<br>
+    assert((data().DefaultedCopyConstructorIsDeleted ||<br>
+            needsOverloadResolutionForCopyConstructor()) &&<br>
+           "Copy constructor should not be deleted");<br>
+    data().DefaultedCopyConstructorIsDeleted = true;<br>
+  }<br>
+<br>
+  /// \brief Set that we attempted to declare an implicit move<br>
   /// constructor, but overload resolution failed so we deleted it.<br>
   void setImplicitMoveConstructorIsDeleted() {<br>
     assert((data().DefaultedMoveConstructorIsDeleted ||<br>
@@ -1315,6 +1373,18 @@ public:<br>
     return data().HasIrrelevantDestructor;<br>
   }<br>
<br>
+  /// \brief Determine whether this class has at least one trivial, non-deleted<br>
+  /// copy or move constructor.<br>
+  bool canPassInRegisters() const {<br>
+    return data().CanPassInRegisters;<br>
+  }<br>
+<br>
+  /// \brief Set that we can pass this RecordDecl in registers.<br>
+  // FIXME: This should be set as part of completeDefinition.<br>
+  void setCanPassInRegisters(bool CanPass) {<br>
+    data().CanPassInRegisters = CanPass;<br>
+  }<br>
+<br>
   /// \brief Determine whether this class has a non-literal or/ volatile type<br>
   /// non-static data member or base class.<br>
   bool hasNonLiteralTypeFieldsOrBases() const {<br>
<br>
Modified: cfe/trunk/lib/AST/ASTImporter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Aug 15 18:49:53 2017<br>
@@ -956,12 +956,16 @@ bool ASTNodeImporter::ImportDefinition(R<br>
     ToData.HasUninitializedFields = FromData.HasUninitializedFields;<br>
     ToData.HasInheritedConstructor = FromData.HasInheritedConstructor;<br>
     ToData.HasInheritedAssignment = FromData.HasInheritedAssignment;<br>
+    ToData.NeedOverloadResolutionForCopyConstructor<br>
+      = FromData.NeedOverloadResolutionForCopyConstructor;<br>
     ToData.NeedOverloadResolutionForMoveConstructor<br>
       = FromData.NeedOverloadResolutionForMoveConstructor;<br>
     ToData.NeedOverloadResolutionForMoveAssignment<br>
       = FromData.NeedOverloadResolutionForMoveAssignment;<br>
     ToData.NeedOverloadResolutionForDestructor<br>
       = FromData.NeedOverloadResolutionForDestructor;<br>
+    ToData.DefaultedCopyConstructorIsDeleted<br>
+      = FromData.DefaultedCopyConstructorIsDeleted;<br>
     ToData.DefaultedMoveConstructorIsDeleted<br>
       = FromData.DefaultedMoveConstructorIsDeleted;<br>
     ToData.DefaultedMoveAssignmentIsDeleted<br>
@@ -973,6 +977,7 @@ bool ASTNodeImporter::ImportDefinition(R<br>
       = FromData.HasConstexprNonCopyMoveConstructor;<br>
     ToData.HasDefaultedDefaultConstructor<br>
       = FromData.HasDefaultedDefaultConstructor;<br>
+    ToData.CanPassInRegisters = FromData.CanPassInRegisters;<br>
     ToData.DefaultedDefaultConstructorIsConstexpr<br>
       = FromData.DefaultedDefaultConstructorIsConstexpr;<br>
     ToData.HasConstexprDefaultConstructor<br>
<br>
Modified: cfe/trunk/lib/AST/DeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Aug 15 18:49:53 2017<br>
@@ -55,15 +55,18 @@ CXXRecordDecl::DefinitionData::Definitio<br>
       HasOnlyCMembers(true), HasInClassInitializer(false),<br>
       HasUninitializedReferenceMember(false), HasUninitializedFields(false),<br>
       HasInheritedConstructor(false), HasInheritedAssignment(false),<br>
+      NeedOverloadResolutionForCopyConstructor(false),<br>
       NeedOverloadResolutionForMoveConstructor(false),<br>
       NeedOverloadResolutionForMoveAssignment(false),<br>
       NeedOverloadResolutionForDestructor(false),<br>
+      DefaultedCopyConstructorIsDeleted(false),<br>
       DefaultedMoveConstructorIsDeleted(false),<br>
       DefaultedMoveAssignmentIsDeleted(false),<br>
       DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All),<br>
       DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true),<br>
       HasConstexprNonCopyMoveConstructor(false),<br>
       HasDefaultedDefaultConstructor(false),<br>
+      CanPassInRegisters(true),<br>
       DefaultedDefaultConstructorIsConstexpr(true),<br>
       HasConstexprDefaultConstructor(false),<br>
       HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),<br>
@@ -352,8 +355,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier<br>
       setHasVolatileMember(true);<br>
<br>
     // Keep track of the presence of mutable fields.<br>
-    if (BaseClassDecl->hasMutableFields())<br>
+    if (BaseClassDecl->hasMutableFields()) {<br>
       data().HasMutableFields = true;<br>
+      data().NeedOverloadResolutionForCopyConstructor = true;<br>
+    }<br>
<br>
     if (BaseClassDecl->hasUninitializedReferenceMember())<br>
       data().HasUninitializedReferenceMember = true;<br>
@@ -406,6 +411,8 @@ void CXXRecordDecl::addedClassSubobject(<br>
   //    -- a direct or virtual base class B that cannot be copied/moved [...]<br>
   //    -- a non-static data member of class type M (or array thereof)<br>
   //       that cannot be copied or moved [...]<br>
+  if (!Subobj->hasSimpleCopyConstructor())<br>
+    data().NeedOverloadResolutionForCopyConstructor = true;<br>
   if (!Subobj->hasSimpleMoveConstructor())<br>
     data().NeedOverloadResolutionForMoveConstructor = true;<br>
<br>
@@ -426,6 +433,7 @@ void CXXRecordDecl::addedClassSubobject(<br>
   //    -- any non-static data member has a type with a destructor<br>
   //       that is deleted or inaccessible from the defaulted [ctor or dtor].<br>
   if (!Subobj->hasSimpleDestructor()) {<br>
+    data().NeedOverloadResolutionForCopyConstructor = true;<br>
     data().NeedOverloadResolutionForMoveConstructor = true;<br>
     data().NeedOverloadResolutionForDestructor = true;<br>
   }<br>
@@ -711,8 +719,10 @@ void CXXRecordDecl::addedMember(Decl *D)<br>
       data().IsStandardLayout = false;<br>
<br>
     // Keep track of the presence of mutable fields.<br>
-    if (Field->isMutable())<br>
+    if (Field->isMutable()) {<br>
       data().HasMutableFields = true;<br>
+      data().NeedOverloadResolutionForCopyConstructor = true;<br>
+    }<br>
<br>
     // C++11 [class.union]p8, DR1460:<br>
     //   If X is a union, a non-static data member of X that is not an anonymous<br>
@@ -756,6 +766,12 @@ void CXXRecordDecl::addedMember(Decl *D)<br>
       //   A standard-layout class is a class that:<br>
       //    -- has no non-static data members of type [...] reference,<br>
       data().IsStandardLayout = false;<br>
+<br>
+      // C++1z [class.copy.ctor]p10:<br>
+      //   A defaulted copy constructor for a class X is defined as deleted if X has:<br>
+      //    -- a non-static data member of rvalue reference type<br>
+      if (T->isRValueReferenceType())<br>
+        data().DefaultedCopyConstructorIsDeleted = true;<br>
     }<br>
<br>
     if (!Field->hasInClassInitializer() && !Field->isMutable()) {<br>
@@ -809,6 +825,10 @@ void CXXRecordDecl::addedMember(Decl *D)<br>
         // We may need to perform overload resolution to determine whether a<br>
         // field can be moved if it's const or volatile qualified.<br>
         if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) {<br>
+          // We need to care about 'const' for the copy constructor because an<br>
+          // implicit copy constructor might be declared with a non-const<br>
+          // parameter.<br>
+          data().NeedOverloadResolutionForCopyConstructor = true;<br>
           data().NeedOverloadResolutionForMoveConstructor = true;<br>
           data().NeedOverloadResolutionForMoveAssignment = true;<br>
         }<br>
@@ -819,6 +839,8 @@ void CXXRecordDecl::addedMember(Decl *D)<br>
         //    -- X is a union-like class that has a variant member with a<br>
         //       non-trivial [corresponding special member]<br>
         if (isUnion()) {<br>
+          if (FieldRec->hasNonTrivialCopyConstructor())<br>
+            data().DefaultedCopyConstructorIsDeleted = true;<br>
           if (FieldRec->hasNonTrivialMoveConstructor())<br>
             data().DefaultedMoveConstructorIsDeleted = true;<br>
           if (FieldRec->hasNonTrivialMoveAssignment())<br>
@@ -830,6 +852,8 @@ void CXXRecordDecl::addedMember(Decl *D)<br>
         // For an anonymous union member, our overload resolution will perform<br>
         // overload resolution for its members.<br>
         if (Field->isAnonymousStructOrUnion()) {<br>
+          data().NeedOverloadResolutionForCopyConstructor |=<br>
+              FieldRec->data().NeedOverloadResolutionForCopyConstructor;<br>
           data().NeedOverloadResolutionForMoveConstructor |=<br>
               FieldRec->data().NeedOverloadResolutionForMoveConstructor;<br>
           data().NeedOverloadResolutionForMoveAssignment |=<br>
@@ -915,8 +939,10 @@ void CXXRecordDecl::addedMember(Decl *D)<br>
         }<br>
<br>
         // Keep track of the presence of mutable fields.<br>
-        if (FieldRec->hasMutableFields())<br>
+        if (FieldRec->hasMutableFields()) {<br>
           data().HasMutableFields = true;<br>
+          data().NeedOverloadResolutionForCopyConstructor = true;<br>
+        }<br>
<br>
         // C++11 [class.copy]p13:<br>
         //   If the implicitly-defined constructor would satisfy the<br>
@@ -1450,7 +1476,7 @@ void CXXRecordDecl::completeDefinition()<br>
<br>
 void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {<br>
   RecordDecl::completeDefinition();<br>
-<br>
+<br>
   // If the class may be abstract (but hasn't been marked as such), check for<br>
   // any pure final overriders.<br>
   if (mayBeAbstract()) {<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Tue Aug 15 18:49:53 2017<br>
@@ -30,38 +30,9 @@ void CGCXXABI::ErrorUnsupportedABI(CodeG<br>
 }<br>
<br>
 bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {<br>
-  // If RD has a non-trivial move or copy constructor, we cannot copy the<br>
-  // argument.<br>
-  if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialMoveConstructor())<br>
-    return false;<br>
-<br>
-  // If RD has a non-trivial destructor, we cannot copy the argument.<br>
-  if (RD->hasNonTrivialDestructor())<br>
-    return false;<br>
-<br>
   // We can only copy the argument if there exists at least one trivial,<br>
   // non-deleted copy or move constructor.<br>
-  // FIXME: This assumes that all lazily declared copy and move constructors are<br>
-  // not deleted.  This assumption might not be true in some corner cases.<br>
-  bool CopyDeleted = false;<br>
-  bool MoveDeleted = false;<br>
-  for (const CXXConstructorDecl *CD : RD->ctors()) {<br>
-    if (CD->isCopyConstructor() || CD->isMoveConstructor()) {<br>
-      assert(CD->isTrivial());<br>
-      // We had at least one undeleted trivial copy or move ctor.  Return<br>
-      // directly.<br>
-      if (!CD->isDeleted())<br>
-        return true;<br>
-      if (CD->isCopyConstructor())<br>
-        CopyDeleted = true;<br>
-      else<br>
-        MoveDeleted = true;<br>
-    }<br>
-  }<br>
-<br>
-  // If all trivial copy and move constructors are deleted, we cannot copy the<br>
-  // argument.<br>
-  return !(CopyDeleted && MoveDeleted);<br>
+  return RD->canPassInRegisters();<br>
 }<br>
<br>
 llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {<br>
<br>
Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Aug 15 18:49:53 2017<br>
@@ -63,11 +63,8 @@ public:<br>
   bool classifyReturnType(CGFunctionInfo &FI) const override;<br>
<br>
   RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {<br>
-    // Structures with either a non-trivial destructor or a non-trivial<br>
-    // copy constructor are always indirect.<br>
-    // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared<br>
-    // special members.<br>
-    if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor())<br>
+    // If C++ prohibits us from making a copy, pass by address.<br>
+    if (!canCopyArgument(RD))<br>
       return RAA_Indirect;<br>
     return RAA_Default;<br>
   }<br>
@@ -1014,10 +1011,8 @@ bool ItaniumCXXABI::classifyReturnType(C<br>
   if (!RD)<br>
     return false;<br>
<br>
-  // Return indirectly if we have a non-trivial copy ctor or non-trivial dtor.<br>
-  // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared<br>
-  // special members.<br>
-  if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) {<br>
+  // If C++ prohibits us from making a copy, return by address.<br>
+  if (!canCopyArgument(RD)) {<br>
     auto Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType());<br>
     FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);<br>
     return true;<br>
<br>
Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Aug 15 18:49:53 2017<br>
@@ -819,46 +819,44 @@ MicrosoftCXXABI::getRecordArgABI(const C<br>
     return RAA_Default;<br>
<br>
   case llvm::Triple::x86_64:<br>
-    // Win64 passes objects with non-trivial copy ctors indirectly.<br>
-    if (RD->hasNonTrivialCopyConstructor())<br>
-      return RAA_Indirect;<br>
-<br>
-    // If an object has a destructor, we'd really like to pass it indirectly<br>
+    // If a class has a destructor, we'd really like to pass it indirectly<br>
     // because it allows us to elide copies.  Unfortunately, MSVC makes that<br>
     // impossible for small types, which it will pass in a single register or<br>
     // stack slot. Most objects with dtors are large-ish, so handle that early.<br>
     // We can't call out all large objects as being indirect because there are<br>
     // multiple x64 calling conventions and the C++ ABI code shouldn't dictate<br>
     // how we pass large POD types.<br>
+    //<br>
+    // Note: This permits small classes with nontrivial destructors to be<br>
+    // passed in registers, which is non-conforming.<br>
     if (RD->hasNonTrivialDestructor() &&<br>
         getContext().getTypeSize(RD->getTypeForDecl()) > 64)<br>
       return RAA_Indirect;<br>
<br>
-    // If this is true, the implicit copy constructor that Sema would have<br>
-    // created would not be deleted. FIXME: We should provide a more direct way<br>
-    // for CodeGen to ask whether the constructor was deleted.<br>
-    if (!RD->hasUserDeclaredCopyConstructor() &&<br>
-        !RD->hasUserDeclaredMoveConstructor() &&<br>
-        !RD->needsOverloadResolutionForMoveConstructor() &&<br>
-        !RD->hasUserDeclaredMoveAssignment() &&<br>
-        !RD->needsOverloadResolutionForMoveAssignment())<br>
-      return RAA_Default;<br>
-<br>
-    // Otherwise, Sema should have created an implicit copy constructor if<br>
-    // needed.<br>
-    assert(!RD->needsImplicitCopyConstructor());<br>
-<br>
-    // We have to make sure the trivial copy constructor isn't deleted.<br>
-    for (const CXXConstructorDecl *CD : RD->ctors()) {<br>
-      if (CD->isCopyConstructor()) {<br>
-        assert(CD->isTrivial());<br>
-        // We had at least one undeleted trivial copy ctor.  Return directly.<br>
-        if (!CD->isDeleted())<br>
-          return RAA_Default;<br>
+    // If a class has at least one non-deleted, trivial copy constructor, it<br>
+    // is passed according to the C ABI. Otherwise, it is passed indirectly.<br>
+    //<br>
+    // Note: This permits classes with non-trivial copy or move ctors to be<br>
+    // passed in registers, so long as they *also* have a trivial copy ctor,<br>
+    // which is non-conforming.<br>
+    if (RD->needsImplicitCopyConstructor()) {<br>
+      // If the copy ctor has not yet been declared, we can read its triviality<br>
+      // off the AST.<br>
+      if (!RD->defaultedCopyConstructorIsDeleted() &&<br>
+          RD->hasTrivialCopyConstructor())<br>
+        return RAA_Default;<br>
+    } else {<br>
+      // Otherwise, we need to find the copy constructor(s) and ask.<br>
+      for (const CXXConstructorDecl *CD : RD->ctors()) {<br>
+        if (CD->isCopyConstructor()) {<br>
+          // We had at least one nondeleted trivial copy ctor.  Return directly.<br>
+          if (!CD->isDeleted() && CD->isTrivial())<br>
+            return RAA_Default;<br>
+        }<br>
       }<br>
     }<br>
<br>
-    // The trivial copy constructor was deleted.  Return indirectly.<br>
+    // We have no trivial, non-deleted copy constructor.<br>
     return RAA_Indirect;<br>
   }<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 15 18:49:53 2017<br>
@@ -5726,6 +5726,53 @@ static void DefineImplicitSpecialMember(<br>
   }<br>
 }<br>
<br>
+/// Determine whether a type is permitted to be passed or returned in<br>
+/// registers, per C++ [class.temporary]p3.<br>
+static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) {<br>
+  if (D->isDependentType() || D->isInvalidDecl())<br>
+    return false;<br>
+<br>
+  // Per C++ [class.temporary]p3, the relevant condition is:<br>
+  //   each copy constructor, move constructor, and destructor of X is<br>
+  //   either trivial or deleted, and X has at least one non-deleted copy<br>
+  //   or move constructor<br>
+  bool HasNonDeletedCopyOrMove = false;<br>
+<br>
+  if (D->needsImplicitCopyConstructor() &&<br>
+      !D->defaultedCopyConstructorIsDeleted()) {<br>
+    if (!D->hasTrivialCopyConstructor())<br>
+      return false;<br>
+    HasNonDeletedCopyOrMove = true;<br>
+  }<br>
+<br>
+  if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() &&<br>
+      !D->defaultedMoveConstructorIsDeleted()) {<br>
+    if (!D->hasTrivialMoveConstructor())<br>
+      return false;<br>
+    HasNonDeletedCopyOrMove = true;<br>
+  }<br>
+<br>
+  if (D->needsImplicitDestructor() && !D->defaultedDestructorIsDeleted() &&<br>
+      !D->hasTrivialDestructor())<br>
+    return false;<br>
+<br>
+  for (const CXXMethodDecl *MD : D->methods()) {<br>
+    if (MD->isDeleted())<br>
+      continue;<br>
+<br>
+    auto *CD = dyn_cast<CXXConstructorDecl>(MD);<br>
+    if (CD && CD->isCopyOrMoveConstructor())<br>
+      HasNonDeletedCopyOrMove = true;<br>
+    else if (!isa<CXXDestructorDecl>(MD))<br>
+      continue;<br>
+<br>
+    if (!MD->isTrivial())<br>
+      return false;<br>
+  }<br>
+<br>
+  return HasNonDeletedCopyOrMove;<br>
+}<br>
+<br>
 /// \brief Perform semantic checks on a class definition that has been<br>
 /// completing, introducing implicitly-declared members, checking for<br>
 /// abstract types, etc.<br>
@@ -5870,6 +5917,8 @@ void Sema::CheckCompletedCXXClass(CXXRec<br>
   }<br>
<br>
   checkClassLevelDLLAttribute(Record);<br>
+<br>
+  Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record));<br>
 }<br>
<br>
 /// Look up the special member function that would be called by a special<br>
@@ -7496,8 +7545,7 @@ void Sema::ActOnFinishCXXMemberSpecifica<br>
               reinterpret_cast<Decl**>(FieldCollector->getCurFields()),<br>
               FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);<br>
<br>
-  CheckCompletedCXXClass(<br>
-                        dyn_cast_or_null<CXXRecordDecl>(TagDecl));<br>
+  CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl));<br>
 }<br>
<br>
 /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared<br>
@@ -11929,8 +11977,10 @@ CXXConstructorDecl *Sema::DeclareImplici<br>
   Scope *S = getScopeForContext(ClassDecl);<br>
   CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);<br>
<br>
-  if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))<br>
+  if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) {<br>
+    ClassDecl->setImplicitCopyConstructorIsDeleted();<br>
     SetDeclDeleted(CopyConstructor, ClassLoc);<br>
+  }<br>
<br>
   if (S)<br>
     PushOnScopeChains(CopyConstructor, S, false);<br>
<br>
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Aug 15 18:49:53 2017<br>
@@ -1559,9 +1559,11 @@ void ASTDeclReader::ReadCXXDefinitionDat<br>
   Data.HasUninitializedFields = Record.readInt();<br>
   Data.HasInheritedConstructor = Record.readInt();<br>
   Data.HasInheritedAssignment = Record.readInt();<br>
+  Data.NeedOverloadResolutionForCopyConstructor = Record.readInt();<br>
   Data.NeedOverloadResolutionForMoveConstructor = Record.readInt();<br>
   Data.NeedOverloadResolutionForMoveAssignment = Record.readInt();<br>
   Data.NeedOverloadResolutionForDestructor = Record.readInt();<br>
+  Data.DefaultedCopyConstructorIsDeleted = Record.readInt();<br>
   Data.DefaultedMoveConstructorIsDeleted = Record.readInt();<br>
   Data.DefaultedMoveAssignmentIsDeleted = Record.readInt();<br>
   Data.DefaultedDestructorIsDeleted = Record.readInt();<br>
@@ -1570,6 +1572,7 @@ void ASTDeclReader::ReadCXXDefinitionDat<br>
   Data.HasIrrelevantDestructor = Record.readInt();<br>
   Data.HasConstexprNonCopyMoveConstructor = Record.readInt();<br>
   Data.HasDefaultedDefaultConstructor = Record.readInt();<br>
+  Data.CanPassInRegisters = Record.readInt();<br>
   Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt();<br>
   Data.HasConstexprDefaultConstructor = Record.readInt();<br>
   Data.HasNonLiteralTypeFieldsOrBases = Record.readInt();<br>
@@ -1697,9 +1700,11 @@ void ASTDeclReader::MergeDefinitionData(<br>
   MATCH_FIELD(HasUninitializedFields)<br>
   MATCH_FIELD(HasInheritedConstructor)<br>
   MATCH_FIELD(HasInheritedAssignment)<br>
+  MATCH_FIELD(NeedOverloadResolutionForCopyConstructor)<br>
   MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)<br>
   MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)<br>
   MATCH_FIELD(NeedOverloadResolutionForDestructor)<br>
+  MATCH_FIELD(DefaultedCopyConstructorIsDeleted)<br>
   MATCH_FIELD(DefaultedMoveConstructorIsDeleted)<br>
   MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)<br>
   MATCH_FIELD(DefaultedDestructorIsDeleted)<br>
@@ -1708,6 +1713,7 @@ void ASTDeclReader::MergeDefinitionData(<br>
   MATCH_FIELD(HasIrrelevantDestructor)<br>
   OR_FIELD(HasConstexprNonCopyMoveConstructor)<br>
   OR_FIELD(HasDefaultedDefaultConstructor)<br>
+  MATCH_FIELD(CanPassInRegisters)<br>
   MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)<br>
   OR_FIELD(HasConstexprDefaultConstructor)<br>
   MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)<br>
<br>
Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Aug 15 18:49:53 2017<br>
@@ -5875,9 +5875,11 @@ void ASTRecordWriter::AddCXXDefinitionDa<br>
   Record->push_back(Data.HasUninitializedFields);<br>
   Record->push_back(Data.HasInheritedConstructor);<br>
   Record->push_back(Data.HasInheritedAssignment);<br>
+  Record->push_back(Data.NeedOverloadResolutionForCopyConstructor);<br>
   Record->push_back(Data.NeedOverloadResolutionForMoveConstructor);<br>
   Record->push_back(Data.NeedOverloadResolutionForMoveAssignment);<br>
   Record->push_back(Data.NeedOverloadResolutionForDestructor);<br>
+  Record->push_back(Data.DefaultedCopyConstructorIsDeleted);<br>
   Record->push_back(Data.DefaultedMoveConstructorIsDeleted);<br>
   Record->push_back(Data.DefaultedMoveAssignmentIsDeleted);<br>
   Record->push_back(Data.DefaultedDestructorIsDeleted);<br>
@@ -5886,6 +5888,7 @@ void ASTRecordWriter::AddCXXDefinitionDa<br>
   Record->push_back(Data.HasIrrelevantDestructor);<br>
   Record->push_back(Data.HasConstexprNonCopyMoveConstructor);<br>
   Record->push_back(Data.HasDefaultedDefaultConstructor);<br>
+  Record->push_back(Data.CanPassInRegisters);<br>
   Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);<br>
   Record->push_back(Data.HasConstexprDefaultConstructor);<br>
   Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp Tue Aug 15 18:49:53 2017<br>
@@ -1,5 +1,6 @@<br>
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s<br>
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s | FileCheck %s -check-prefix=WIN64<br>
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s -fms-compatibility -fms-compatibility-version=18 | FileCheck %s -check-prefix=WIN64 -check-prefix=WIN64-18<br>
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s -fms-compatibility -fms-compatibility-version=19 | FileCheck %s -check-prefix=WIN64 -check-prefix=WIN64-19<br>
<br>
 namespace trivial {<br>
 // Trivial structs should be passed directly.<br>
@@ -52,12 +53,11 @@ void foo(A);<br>
 void bar() {<br>
   foo({});<br>
 }<br>
-// FIXME: The copy ctor is implicitly deleted.<br>
-// CHECK-DISABLED-LABEL: define void @_ZN9move_ctor3barEv()<br>
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(<br>
-// CHECK-DISABLED-NOT: call<br>
-// CHECK-DISABLED: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})<br>
-// CHECK-DISABLED-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)<br>
+// CHECK-LABEL: define void @_ZN9move_ctor3barEv()<br>
+// CHECK: call void @_Z{{.*}}C1Ev(<br>
+// CHECK-NOT: call<br>
+// CHECK: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})<br>
+// CHECK-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)<br>
<br>
 // WIN64-LABEL: declare void @"\01?foo@move_ctor@@YAXUA@1@@Z"(%"struct.move_ctor::A"*)<br>
 }<br>
@@ -73,12 +73,11 @@ void foo(A);<br>
 void bar() {<br>
   foo({});<br>
 }<br>
-// FIXME: The copy ctor is deleted.<br>
-// CHECK-DISABLED-LABEL: define void @_ZN11all_deleted3barEv()<br>
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(<br>
-// CHECK-DISABLED-NOT: call<br>
-// CHECK-DISABLED: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})<br>
-// CHECK-DISABLED-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)<br>
+// CHECK-LABEL: define void @_ZN11all_deleted3barEv()<br>
+// CHECK: call void @_Z{{.*}}C1Ev(<br>
+// CHECK-NOT: call<br>
+// CHECK: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})<br>
+// CHECK-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)<br>
<br>
 // WIN64-LABEL: declare void @"\01?foo@all_deleted@@YAXUA@1@@Z"(%"struct.all_deleted::A"*)<br>
 }<br>
@@ -93,14 +92,15 @@ void foo(A);<br>
 void bar() {<br>
   foo({});<br>
 }<br>
-// FIXME: The copy and move ctors are implicitly deleted.<br>
-// CHECK-DISABLED-LABEL: define void @_ZN18implicitly_deleted3barEv()<br>
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(<br>
-// CHECK-DISABLED-NOT: call<br>
-// CHECK-DISABLED: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}})<br>
-// CHECK-DISABLED-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)<br>
-<br>
-// WIN64-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(%"struct.implicitly_deleted::A"*)<br>
+// CHECK-LABEL: define void @_ZN18implicitly_deleted3barEv()<br>
+// CHECK: call void @_Z{{.*}}C1Ev(<br>
+// CHECK-NOT: call<br>
+// CHECK: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}})<br>
+// CHECK-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)<br>
+<br>
+// In MSVC 2013, the copy ctor is not deleted by a move assignment. In MSVC 2015, it is.<br>
+// WIN64-18-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(i64<br>
+// WIN64-19-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(%"struct.implicitly_deleted::A"*)<br>
 }<br>
<br>
 namespace one_deleted {<br>
@@ -113,12 +113,11 @@ void foo(A);<br>
 void bar() {<br>
   foo({});<br>
 }<br>
-// FIXME: The copy constructor is implicitly deleted.<br>
-// CHECK-DISABLED-LABEL: define void @_ZN11one_deleted3barEv()<br>
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(<br>
-// CHECK-DISABLED-NOT: call<br>
-// CHECK-DISABLED: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})<br>
-// CHECK-DISABLED-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)<br>
+// CHECK-LABEL: define void @_ZN11one_deleted3barEv()<br>
+// CHECK: call void @_Z{{.*}}C1Ev(<br>
+// CHECK-NOT: call<br>
+// CHECK: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})<br>
+// CHECK-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)<br>
<br>
 // WIN64-LABEL: declare void @"\01?foo@one_deleted@@YAXUA@1@@Z"(%"struct.one_deleted::A"*)<br>
 }<br>
@@ -195,12 +194,10 @@ void foo(B);<br>
 void bar() {<br>
   foo({});<br>
 }<br>
-// FIXME: This class has a non-trivial copy ctor and a trivial copy ctor.  It's<br>
-// not clear whether we should pass by address or in registers.<br>
-// CHECK-DISABLED-LABEL: define void @_ZN14two_copy_ctors3barEv()<br>
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(<br>
-// CHECK-DISABLED: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})<br>
-// CHECK-DISABLED-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)<br>
+// CHECK-LABEL: define void @_ZN14two_copy_ctors3barEv()<br>
+// CHECK: call void @_Z{{.*}}C1Ev(<br>
+// CHECK: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})<br>
+// CHECK-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)<br>
<br>
 // WIN64-LABEL: declare void @"\01?foo@two_copy_ctors@@YAXUB@1@@Z"(%"struct.two_copy_ctors::B"*)<br>
 }<br>
@@ -212,6 +209,7 @@ struct A {<br>
   void *p;<br>
 };<br>
 void *foo(A a) { return a.p; }<br>
+// CHECK-LABEL: define i8* @_ZN15definition_only3fooENS_1AE(%"struct.definition_only::A"*<br>
 // WIN64-LABEL: define i8* @"\01?foo@definition_only@@YAPEAXUA@1@@Z"(%"struct.definition_only::A"*<br>
 }<br>
<br>
@@ -226,6 +224,7 @@ struct A {<br>
   B b;<br>
 };<br>
 void *foo(A a) { return a.b.p; }<br>
+// CHECK-LABEL: define i8* @_ZN17deleted_by_member3fooENS_1AE(%"struct.deleted_by_member::A"*<br>
 // WIN64-LABEL: define i8* @"\01?foo@deleted_by_member@@YAPEAXUA@1@@Z"(%"struct.deleted_by_member::A"*<br>
 }<br>
<br>
@@ -239,6 +238,7 @@ struct A : B {<br>
   A();<br>
 };<br>
 void *foo(A a) { return a.p; }<br>
+// CHECK-LABEL: define i8* @_ZN15deleted_by_base3fooENS_1AE(%"struct.deleted_by_base::A"*<br>
 // WIN64-LABEL: define i8* @"\01?foo@deleted_by_base@@YAPEAXUA@1@@Z"(%"struct.deleted_by_base::A"*<br>
 }<br>
<br>
@@ -253,6 +253,7 @@ struct A {<br>
   B b;<br>
 };<br>
 void *foo(A a) { return a.b.p; }<br>
+// CHECK-LABEL: define i8* @_ZN22deleted_by_member_copy3fooENS_1AE(%"struct.deleted_by_member_copy::A"*<br>
 // WIN64-LABEL: define i8* @"\01?foo@deleted_by_member_copy@@YAPEAXUA@1@@Z"(%"struct.deleted_by_member_copy::A"*<br>
 }<br>
<br>
@@ -266,6 +267,7 @@ struct A : B {<br>
   A();<br>
 };<br>
 void *foo(A a) { return a.p; }<br>
+// CHECK-LABEL: define i8* @_ZN20deleted_by_base_copy3fooENS_1AE(%"struct.deleted_by_base_copy::A"*<br>
 // WIN64-LABEL: define i8* @"\01?foo@deleted_by_base_copy@@YAPEAXUA@1@@Z"(%"struct.deleted_by_base_copy::A"*<br>
 }<br>
<br>
@@ -275,6 +277,75 @@ struct A {<br>
   A(const A &o) = delete;<br>
   void *p;<br>
 };<br>
+// CHECK-LABEL: define i8* @_ZN15explicit_delete3fooENS_1AE(%"struct.explicit_delete::A"*<br>
 // WIN64-LABEL: define i8* @"\01?foo@explicit_delete@@YAPEAXUA@1@@Z"(%"struct.explicit_delete::A"*<br>
 void *foo(A a) { return a.p; }<br>
 }<br>
+<br>
+namespace implicitly_deleted_copy_ctor {<br>
+struct A {<br>
+  // No move ctor due to copy assignment.<br>
+  A &operator=(const A&);<br>
+  // Deleted copy ctor due to rvalue ref member.<br>
+  int &&ref;<br>
+};<br>
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(%"struct.implicitly_deleted_copy_ctor::A"*<br>
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAAEAHUA@1@@Z"(%"struct.implicitly_deleted_copy_ctor::A"*<br>
+int &foo(A a) { return a.ref; }<br>
+<br>
+struct B {<br>
+  // Passed direct: has non-deleted trivial copy ctor.<br>
+  B &operator=(const B&);<br>
+  int &ref;<br>
+};<br>
+int &foo(B b) { return b.ref; }<br>
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1BE(i32*<br>
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAAEAHUB@1@@Z"(i64<br>
+<br>
+struct X { X(const X&); };<br>
+struct Y { Y(const Y&) = default; };<br>
+<br>
+union C {<br>
+  C &operator=(const C&);<br>
+  // Passed indirect: copy ctor deleted due to variant member with nontrivial copy ctor.<br>
+  X x;<br>
+  int n;<br>
+};<br>
+int foo(C c) { return c.n; }<br>
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1CE(%"union.implicitly_deleted_copy_ctor::C"*<br>
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAHTC@1@@Z"(%"union.implicitly_deleted_copy_ctor::C"*<br>
+<br>
+struct D {<br>
+  D &operator=(const D&);<br>
+  // Passed indirect: copy ctor deleted due to variant member with nontrivial copy ctor.<br>
+  union {<br>
+    X x;<br>
+    int n;<br>
+  };<br>
+};<br>
+int foo(D d) { return d.n; }<br>
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1DE(%"struct.implicitly_deleted_copy_ctor::D"*<br>
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAHUD@1@@Z"(%"struct.implicitly_deleted_copy_ctor::D"*<br>
+<br>
+union E {<br>
+  // Passed direct: has non-deleted trivial copy ctor.<br>
+  E &operator=(const E&);<br>
+  Y y;<br>
+  int n;<br>
+};<br>
+int foo(E e) { return e.n; }<br>
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1EE(i32<br>
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAHTE@1@@Z"(i32<br>
+<br>
+struct F {<br>
+  // Passed direct: has non-deleted trivial copy ctor.<br>
+  F &operator=(const F&);<br>
+  union {<br>
+    Y y;<br>
+    int n;<br>
+  };<br>
+};<br>
+int foo(F f) { return f.n; }<br>
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1FE(i32<br>
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAHUF@1@@Z"(i32<br>
+}<br>
<br>
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=310983&r1=310982&r2=310983&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=310983&r1=310982&r2=310983&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (original)<br>
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Tue Aug 15 18:49:53 2017<br>
@@ -1108,26 +1108,35 @@ TEST(ConstructorDeclaration, IsExplicit)<br>
 }<br>
<br>
 TEST(ConstructorDeclaration, Kinds) {<br>
-  EXPECT_TRUE(matches("struct S { S(); };",<br>
-                      cxxConstructorDecl(isDefaultConstructor())));<br>
-  EXPECT_TRUE(notMatches("struct S { S(); };",<br>
-                         cxxConstructorDecl(isCopyConstructor())));<br>
-  EXPECT_TRUE(notMatches("struct S { S(); };",<br>
-                         cxxConstructorDecl(isMoveConstructor())));<br>
+  EXPECT_TRUE(matches(<br>
+      "struct S { S(); };",<br>
+      cxxConstructorDecl(isDefaultConstructor(), unless(isImplicit()))));<br>
+  EXPECT_TRUE(notMatches(<br>
+      "struct S { S(); };",<br>
+      cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));<br>
+  EXPECT_TRUE(notMatches(<br>
+      "struct S { S(); };",<br>
+      cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));<br>
<br>
-  EXPECT_TRUE(notMatches("struct S { S(const S&); };",<br>
-                         cxxConstructorDecl(isDefaultConstructor())));<br>
-  EXPECT_TRUE(matches("struct S { S(const S&); };",<br>
-                      cxxConstructorDecl(isCopyConstructor())));<br>
-  EXPECT_TRUE(notMatches("struct S { S(const S&); };",<br>
-                         cxxConstructorDecl(isMoveConstructor())));<br>
+  EXPECT_TRUE(notMatches(<br>
+      "struct S { S(const S&); };",<br>
+      cxxConstructorDecl(isDefaultConstructor(), unless(isImplicit()))));<br>
+  EXPECT_TRUE(matches(<br>
+      "struct S { S(const S&); };",<br>
+      cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));<br>
+  EXPECT_TRUE(notMatches(<br>
+      "struct S { S(const S&); };",<br>
+      cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));<br>
<br>
-  EXPECT_TRUE(notMatches("struct S { S(S&&); };",<br>
-                         cxxConstructorDecl(isDefaultConstructor())));<br>
-  EXPECT_TRUE(notMatches("struct S { S(S&&); };",<br>
-                         cxxConstructorDecl(isCopyConstructor())));<br>
-  EXPECT_TRUE(matches("struct S { S(S&&); };",<br>
-                      cxxConstructorDecl(isMoveConstructor())));<br>
+  EXPECT_TRUE(notMatches(<br>
+      "struct S { S(S&&); };",<br>
+      cxxConstructorDecl(isDefaultConstructor(), unless(isImplicit()))));<br>
+  EXPECT_TRUE(notMatches(<br>
+      "struct S { S(S&&); };",<br>
+      cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));<br>
+  EXPECT_TRUE(matches(<br>
+      "struct S { S(S&&); };",<br>
+      cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));<br>
 }<br>
<br>
 TEST(ConstructorDeclaration, IsUserProvided) {<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div></div></div></div>
<br>_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
<br></blockquote></div></div></div></blockquote></div>