Thanks for a quick response, "#include <string>" indeed helped.
On Thu, Aug 17, 2017 at 5:41 PM Richard Smith <rich...@metafoo.co.uk> wrote: > On 17 August 2017 at 17:28, Petr Hosek via cfe-commits < > cfe-commits@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@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@move_ctor@@YAXUA@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@all_deleted@@YAXUA@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@implicitly_deleted@@YAXUA@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@implicitly_deleted@@YAXUA@1 >>> @@Z"(i64 >>> +// WIN64-19-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@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@one_deleted@@YAXUA@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@two_copy_ctors@@YAXUB@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@definition_only@@YAPEAXUA@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@deleted_by_member@@YAPEAXUA@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@deleted_by_base@@YAPEAXUA@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@deleted_by_member_copy@@YAPEAXUA@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@deleted_by_base_copy@@YAPEAXUA@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@explicit_delete@@YAPEAXUA@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@implicitly_deleted_copy_ctor >>> @@YAAEAHUA@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@implicitly_deleted_copy_ctor >>> @@YAAEAHUB@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@implicitly_deleted_copy_ctor >>> @@YAHTC@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@implicitly_deleted_copy_ctor >>> @@YAHUD@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@implicitly_deleted_copy_ctor >>> @@YAHTE@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@implicitly_deleted_copy_ctor >>> @@YAHUF@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@lists.llvm.org >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >>> >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> >>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits