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