r310983 - PR19668, PR23034: Fix handling of move constructors and deleted copy

Petr Hosek via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 17 18:12:13 PDT 2017


Thanks for a quick response, "#include <string>" indeed helped.

On Thu, Aug 17, 2017 at 5:41 PM Richard Smith <richard at metafoo.co.uk> wrote:

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


More information about the cfe-commits mailing list