[clang] d052a57 - [c++2a] Allow comparison functions to be explicitly defaulted.
Hubert Tong via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 10 18:01:00 PDT 2020
On Tue, Mar 10, 2020 at 7:35 PM Richard Smith <richard at metafoo.co.uk> wrote:
> Should be fixed in llvmorg-11-init-5426-g4cba668ac13.
>
Thanks. We're also seeing a failure on valid code where a template class
explicitly deletes a function that is an override of an explicitly deleted
virtual function in a (non-templated) base class.
<stdin>:7:16: error: non-deleted function 'f' cannot override a deleted
function
virtual void f() = delete;
^
<stdin>:10:8: note: in instantiation of template class 'B<int>' requested
here
B<int> b() { return {}; }
^
<stdin>:2:16: note: overridden virtual function is here
virtual void f() = delete;
^
1 error generated.
>
> On Sat, 7 Mar 2020 at 08:05, Hubert Tong via cfe-commits <
> cfe-commits at lists.llvm.org> wrote:
>
>> Following this commit, the error recovery for invalid cases that
>> explicitly define (out-of-line) a member function template as deleted and
>> attempts to instantiate said function appears broken.
>>
>> <stdin>:4:35: error: deleted definition must be first declaration
>> template <typename> void A::f() = delete;
>> ^
>> <stdin>:2:35: note: previous declaration is here
>> template <typename> static void f();
>> ^
>> clang:
>> /src_d052a578de58cbbb638cbe2dba05242d1ff443b9/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp:4288:
>> void clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation,
>> clang::FunctionDecl *, bool, bool, bool): Assertion `(Pattern ||
>> PatternDecl->isDefaulted() || PatternDecl->hasSkippedBody()) && "unexpected
>> kind of function template definition"' failed.
>> Stack dump:
>> 0. Program arguments:
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/clang -cc1 -std=c++11
>> -xc++ -
>> 1. <stdin>:5:26: current parser token ';'
>> #0 0x00003fff7fe6a024 PrintStackTraceSignalHandler(void*)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libLLVMSupport.so.10svn+0x1ea024)
>> #1 0x00003fff7fe670c8 llvm::sys::RunSignalHandlers()
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libLLVMSupport.so.10svn+0x1e70c8)
>> #2 0x00003fff7fe6a49c SignalHandler(int)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libLLVMSupport.so.10svn+0x1ea49c)
>> #3 0x00003fff82030478 0x478 abort
>> #4 0x00003fff82030478
>> #5 0x00003fff82030478 __assert_fail_base (+0x478)
>> #6 0x00003fff7e0a1f94 __assert_fail (/lib64/libc.so.6+0x41f94)
>> #7 0x00003fff7e0955d4
>> clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation,
>> clang::FunctionDecl*, bool, bool, bool) (/lib64/libc.so.6+0x355d4)
>> #8 0x00003fff7e0956c4
>> clang::Sema::ActOnExplicitInstantiation(clang::Scope*,
>> clang::SourceLocation, clang::SourceLocation, clang::Declarator&)
>> (/lib64/libc.so.6+0x356c4)
>> #9 0x00003fff7c28d604
>> clang::Parser::ParseDeclarationAfterDeclaratorAndAttributes(clang::Declarator&,
>> clang::Parser::ParsedTemplateInfo const&, clang::Parser::ForRangeInit*)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangSema.so.10svn+0x8ad604)
>> #10 0x00003fff7c15c2b0
>> clang::Parser::ParseDeclarationAfterDeclarator(clang::Declarator&,
>> clang::Parser::ParsedTemplateInfo const&)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangSema.so.10svn+0x77c2b0)
>> #11 0x00003fff7c4cc8f8
>> clang::Parser::ParseSingleDeclarationAfterTemplate(clang::DeclaratorContext,
>> clang::Parser::ParsedTemplateInfo const&, clang::ParsingDeclRAIIObject&,
>> clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0x4c8f8)
>> #12 0x00003fff7c4cdf48
>> clang::Parser::ParseExplicitInstantiation(clang::DeclaratorContext,
>> clang::SourceLocation, clang::SourceLocation, clang::SourceLocation&,
>> clang::ParsedAttributes&, clang::AccessSpecifier)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0x4df48)
>> #13 0x00003fff7c57c1f0
>> clang::Parser::ParseDeclarationStartingWithTemplate(clang::DeclaratorContext,
>> clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0xfc1f0)
>> #14 0x00003fff7c57a6c0
>> clang::Parser::ParseDeclaration(clang::DeclaratorContext,
>> clang::SourceLocation&, clang::Parser::ParsedAttributesWithRange&,
>> clang::SourceLocation*)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0xfa6c0)
>> #15 0x00003fff7c57a4f8
>> clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&,
>> clang::ParsingDeclSpec*)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0xfa4f8)
>> #16 0x00003fff7c4c5db0
>> clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&,
>> bool)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0x45db0)
>> #17 0x00003fff7c58fffc clang::ParseAST(clang::Sema&, bool, bool)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0x10fffc)
>> #18 0x00003fff7c58def4 clang::ASTFrontendAction::ExecuteAction()
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0x10def4)
>> #19 0x00003fff7c4b01e0 clang::FrontendAction::Execute()
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn+0x301e0)
>> #20 0x00003fff7e93d57c
>> clang::CompilerInstance::ExecuteAction(clang::FrontendAction&)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libclangFrontend.so.10svn+0x10d57c)
>> #21 0x00003fff7e93cbf0
>> clang::ExecuteCompilerInvocation(clang::CompilerInstance*)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libclangFrontend.so.10svn+0x10cbf0)
>> #22 0x00003fff7e8d5bd4 cc1_main(llvm::ArrayRef<char const*>, char const*,
>> void*)
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libclangFrontend.so.10svn+0xa5bd4)
>> #23 0x00003fff7e8042f0 main
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libclangFrontendTool.so.10svn+0x42f0)
>> #24 0x0000000010012594 generic_start_main.isra.0
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/clang+0x10012594)
>> #25 0x000000001000f37c __libc_start_main
>> (/build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/clang+0x1000f37c)
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libLLVMSupport.so.10svn(+0x1ea024)[0x3fff7fe6a024]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libLLVMSupport.so.10svn(_ZN4llvm3sys17RunSignalHandlersEv+0xc8)[0x3fff7fe670c8]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libLLVMSupport.so.10svn(+0x1ea49c)[0x3fff7fe6a49c]
>> [0x3fff82030478]
>> /lib64/libc.so.6(abort+0x2b4)[0x3fff7e0a1f94]
>> /lib64/libc.so.6(+0x355d4)[0x3fff7e0955d4]
>> /lib64/libc.so.6(__assert_fail+0x64)[0x3fff7e0956c4]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangSema.so.10svn(_ZN5clang4Sema29InstantiateFunctionDefinitionENS_14SourceLocationEPNS_12FunctionDeclEbbb+0x1244)[0x3fff7c28d604]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangSema.so.10svn(_ZN5clang4Sema26ActOnExplicitInstantiationEPNS_5ScopeENS_14SourceLocationES3_RNS_10DeclaratorE+0x2290)[0x3fff7c15c2b0]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang6Parser44ParseDeclarationAfterDeclaratorAndAttributesERNS_10DeclaratorERKNS0_18ParsedTemplateInfoEPNS0_12ForRangeInitE+0xf8)[0x3fff7c4cc8f8]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang6Parser31ParseDeclarationAfterDeclaratorERNS_10DeclaratorERKNS0_18ParsedTemplateInfoE+0x98)[0x3fff7c4cdf48]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang6Parser35ParseSingleDeclarationAfterTemplateENS_17DeclaratorContextERKNS0_18ParsedTemplateInfoERNS_21ParsingDeclRAIIObjectERNS_14SourceLocationERNS_16ParsedAttributesENS_15AccessSpecifierE+0x950)[0x3fff7c57c1f0]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang6Parser26ParseExplicitInstantiationENS_17DeclaratorContextENS_14SourceLocationES2_RS2_RNS_16ParsedAttributesENS_15AccessSpecifierE+0x80)[0x3fff7c57a6c0]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang6Parser36ParseDeclarationStartingWithTemplateENS_17DeclaratorContextERNS_14SourceLocationERNS_16ParsedAttributesENS_15AccessSpecifierE+0x158)[0x3fff7c57a4f8]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang6Parser16ParseDeclarationENS_17DeclaratorContextERNS_14SourceLocationERNS0_25ParsedAttributesWithRangeEPS2_+0x350)[0x3fff7c4c5db0]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang6Parser24ParseExternalDeclarationERNS0_25ParsedAttributesWithRangeEPNS_15ParsingDeclSpecE+0x2bc)[0x3fff7c58fffc]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang6Parser17ParseTopLevelDeclERNS_9OpaquePtrINS_12DeclGroupRefEEEb+0x614)[0x3fff7c58def4]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/../lib/libclangParse.so.10svn(_ZN5clang8ParseASTERNS_4SemaEbb+0x2c0)[0x3fff7c4b01e0]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libclangFrontend.so.10svn(_ZN5clang17ASTFrontendAction13ExecuteActionEv+0xdc)[0x3fff7e93d57c]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libclangFrontend.so.10svn(_ZN5clang14FrontendAction7ExecuteEv+0x150)[0x3fff7e93cbf0]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libclangFrontend.so.10svn(_ZN5clang16CompilerInstance13ExecuteActionERNS_14FrontendActionE+0x714)[0x3fff7e8d5bd4]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/../lib/libclangFrontendTool.so.10svn(_ZN5clang25ExecuteCompilerInvocationEPNS_16CompilerInstanceE+0x830)[0x3fff7e8042f0]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/clang(_Z8cc1_mainN4llvm8ArrayRefIPKcEES2_Pv+0x674)[0x10012594]
>>
>> /build_d052a578de58cbbb638cbe2dba05242d1ff443b9/bin/clang(main+0x321c)[0x1000f37c]
>> /lib64/libc.so.6(+0x25100)[0x3fff7e085100]
>> /lib64/libc.so.6(__libc_start_main+0xc4)[0x3fff7e0852f4]
>>
>>
>> On Tue, Oct 22, 2019 at 9:18 PM Richard Smith via cfe-commits <
>> cfe-commits at lists.llvm.org> wrote:
>>
>>>
>>> Author: Richard Smith
>>> Date: 2019-10-22T18:16:17-07:00
>>> New Revision: d052a578de58cbbb638cbe2dba05242d1ff443b9
>>>
>>> URL:
>>> https://github.com/llvm/llvm-project/commit/d052a578de58cbbb638cbe2dba05242d1ff443b9
>>> DIFF:
>>> https://github.com/llvm/llvm-project/commit/d052a578de58cbbb638cbe2dba05242d1ff443b9.diff
>>>
>>> LOG: [c++2a] Allow comparison functions to be explicitly defaulted.
>>>
>>> This adds some initial syntactic checking that only the appropriate
>>> function signatures can be defaulted. No implicit definitions are
>>> generated yet.
>>>
>>> Added:
>>> clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
>>> clang/test/CXX/class/class.compare/class.eq/p1.cpp
>>> clang/test/CXX/class/class.compare/class.rel/p1.cpp
>>>
>>> Modified:
>>> clang/include/clang/AST/Decl.h
>>> clang/include/clang/Basic/DiagnosticCommonKinds.td
>>> clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> clang/include/clang/Sema/Sema.h
>>> clang/lib/AST/Decl.cpp
>>> clang/lib/Parse/ParseDecl.cpp
>>> clang/lib/Parse/ParseDeclCXX.cpp
>>> clang/lib/Sema/SemaDecl.cpp
>>> clang/lib/Sema/SemaDeclCXX.cpp
>>> clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
>>> clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
>>> clang/test/Parser/cxx0x-decl.cpp
>>> clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
>>> clang/test/SemaCXX/cxx17-compat.cpp
>>>
>>> Removed:
>>>
>>>
>>>
>>>
>>> ################################################################################
>>> diff --git a/clang/include/clang/AST/Decl.h
>>> b/clang/include/clang/AST/Decl.h
>>> index ce674e09c44d..b3e7a570fd6d 100644
>>> --- a/clang/include/clang/AST/Decl.h
>>> +++ b/clang/include/clang/AST/Decl.h
>>> @@ -59,6 +59,7 @@ class EnumDecl;
>>> class Expr;
>>> class FunctionTemplateDecl;
>>> class FunctionTemplateSpecializationInfo;
>>> +class FunctionTypeLoc;
>>> class LabelStmt;
>>> class MemberSpecializationInfo;
>>> class Module;
>>> @@ -2362,6 +2363,12 @@ class FunctionDecl : public DeclaratorDecl,
>>> /// parameters have default arguments (in C++).
>>> unsigned getMinRequiredArguments() const;
>>>
>>> + /// Find the source location information for how the type of this
>>> function
>>> + /// was written. May be absent (for example if the function was
>>> declared via
>>> + /// a typedef) and may contain a
>>> diff erent type from that of the function
>>> + /// (for example if the function type was adjusted by an attribute).
>>> + FunctionTypeLoc getFunctionTypeLoc() const;
>>> +
>>> QualType getReturnType() const {
>>> return getType()->castAs<FunctionType>()->getReturnType();
>>> }
>>>
>>> diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td
>>> b/clang/include/clang/Basic/DiagnosticCommonKinds.td
>>> index 6018c1417789..7a416c282e3d 100644
>>> --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
>>> +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
>>> @@ -87,7 +87,8 @@ def warn_cxx98_compat_variadic_templates :
>>> Warning<"variadic templates are incompatible with C++98">,
>>> InGroup<CXX98Compat>, DefaultIgnore;
>>> def err_default_special_members : Error<
>>> - "only special member functions may be defaulted">;
>>> + "only special member functions %select{|and comparison operators }0"
>>> + "may be defaulted">;
>>> def err_deleted_non_function : Error<
>>> "only functions can have deleted definitions">;
>>> def err_module_not_found : Error<"module '%0' not found">, DefaultFatal;
>>>
>>> diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> b/clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> index d802a92c42c0..f7b98bb9ea86 100644
>>> --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> @@ -8099,6 +8099,31 @@ def note_vbase_moved_here : Note<
>>> "%select{%1 is a virtual base class of base class %2 declared here|"
>>> "virtual base class %1 declared here}0">;
>>>
>>> +// C++20 defaulted comparisons
>>> +// This corresponds to values of Sema::DefaultedComparisonKind.
>>> +def select_defaulted_comparison_kind : TextSubstitution<
>>> + "%select{<ERROR>|equality|three-way|equality|relational}0 comparison "
>>> + "operator">;
>>> +def ext_defaulted_comparison : ExtWarn<
>>> + "defaulted comparison operators are a C++20 extension">,
>>> InGroup<CXX2a>;
>>> +def warn_cxx17_compat_defaulted_comparison : Warning<
>>> + "defaulted comparison operators are incompatible with C++ standards "
>>> + "before C++20">, InGroup<CXXPre2aCompat>, DefaultIgnore;
>>> +def err_defaulted_comparison_template : Error<
>>> + "comparison operator template cannot be defaulted">;
>>> +def err_defaulted_comparison_out_of_class : Error<
>>> + "%sub{select_defaulted_comparison_kind}0 can only be defaulted in a
>>> class "
>>> + "definition">;
>>> +def err_defaulted_comparison_param : Error<
>>> + "invalid parameter type for defaulted
>>> %sub{select_defaulted_comparison_kind}0"
>>> + "%
>>> diff {; found $, expected $|}1,2">;
>>> +def err_defaulted_comparison_non_const : Error<
>>> + "defaulted member %sub{select_defaulted_comparison_kind}0 must be "
>>> + "const-qualified">;
>>> +def err_defaulted_comparison_return_type_not_bool : Error<
>>> + "return type for defaulted %sub{select_defaulted_comparison_kind}0 "
>>> + "must be 'bool', not %1">;
>>> +
>>> def ext_implicit_exception_spec_mismatch : ExtWarn<
>>> "function previously declared with an %select{explicit|implicit}0
>>> exception "
>>> "specification redeclared with an %select{implicit|explicit}0
>>> exception "
>>>
>>> diff --git a/clang/include/clang/Sema/Sema.h
>>> b/clang/include/clang/Sema/Sema.h
>>> index a911c61a07f8..3058f862c6ec 100644
>>> --- a/clang/include/clang/Sema/Sema.h
>>> +++ b/clang/include/clang/Sema/Sema.h
>>> @@ -1237,6 +1237,24 @@ class Sema {
>>> /// same special member, we should act as if it is not yet declared.
>>> llvm::SmallPtrSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared;
>>>
>>> + /// Kinds of defaulted comparison operator functions.
>>> + enum class DefaultedComparisonKind {
>>> + /// This is not a defaultable comparison operator.
>>> + None,
>>> + /// This is an operator== that should be implemented as a series of
>>> + /// subobject comparisons.
>>> + Equal,
>>> + /// This is an operator<=> that should be implemented as a series of
>>> + /// subobject comparisons.
>>> + ThreeWay,
>>> + /// This is an operator!= that should be implemented as a rewrite
>>> in terms
>>> + /// of a == comparison.
>>> + NotEqual,
>>> + /// This is an <, <=, >, or >= that should be implemented as a
>>> rewrite in
>>> + /// terms of a <=> comparison.
>>> + Relational,
>>> + };
>>> +
>>> /// The function definitions which were renamed as part of
>>> typo-correction
>>> /// to match their respective declarations. We want to keep track of
>>> them
>>> /// to ensure that we don't emit a "redefinition" error if we
>>> encounter a
>>> @@ -2541,7 +2559,52 @@ class Sema {
>>> bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
>>> TrivialABIHandling TAH =
>>> TAH_IgnoreTrivialABI,
>>> bool Diagnose = false);
>>> - CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
>>> +
>>> + /// For a defaulted function, the kind of defaulted function that it
>>> is.
>>> + class DefaultedFunctionKind {
>>> + CXXSpecialMember SpecialMember : 8;
>>> + DefaultedComparisonKind Comparison : 8;
>>> +
>>> + public:
>>> + DefaultedFunctionKind()
>>> + : SpecialMember(CXXInvalid),
>>> Comparison(DefaultedComparisonKind::None) {
>>> + }
>>> + DefaultedFunctionKind(CXXSpecialMember CSM)
>>> + : SpecialMember(CSM), Comparison(DefaultedComparisonKind::None)
>>> {}
>>> + DefaultedFunctionKind(DefaultedComparisonKind Comp)
>>> + : SpecialMember(CXXInvalid), Comparison(Comp) {}
>>> +
>>> + bool isSpecialMember() const { return SpecialMember != CXXInvalid; }
>>> + bool isComparison() const {
>>> + return Comparison != DefaultedComparisonKind::None;
>>> + }
>>> +
>>> + explicit operator bool() const {
>>> + return isSpecialMember() || isComparison();
>>> + }
>>> +
>>> + CXXSpecialMember asSpecialMember() const { return SpecialMember; }
>>> + DefaultedComparisonKind asComparison() const { return Comparison; }
>>> +
>>> + /// Get the index of this function kind for use in diagnostics.
>>> + unsigned getDiagnosticIndex() const {
>>> + static_assert(CXXInvalid > CXXDestructor,
>>> + "invalid should have highest index");
>>> + static_assert((unsigned)DefaultedComparisonKind::None == 0,
>>> + "none should be equal to zero");
>>> + return SpecialMember + (unsigned)Comparison;
>>> + }
>>> + };
>>> +
>>> + DefaultedFunctionKind getDefaultedFunctionKind(const FunctionDecl
>>> *FD);
>>> +
>>> + CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD) {
>>> + return getDefaultedFunctionKind(MD).asSpecialMember();
>>> + }
>>> + DefaultedComparisonKind getDefaultedComparisonKind(const FunctionDecl
>>> *FD) {
>>> + return getDefaultedFunctionKind(FD).asComparison();
>>> + }
>>> +
>>> void ActOnLastBitfield(SourceLocation DeclStart,
>>> SmallVectorImpl<Decl *> &AllIvarDecls);
>>> Decl *ActOnIvar(Scope *S, SourceLocation DeclStart,
>>> @@ -6361,9 +6424,15 @@ class Sema {
>>> StorageClass &SC);
>>> void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD);
>>>
>>> - void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
>>> + void CheckExplicitlyDefaultedFunction(FunctionDecl *MD);
>>> +
>>> + bool CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
>>> + CXXSpecialMember CSM);
>>> void CheckDelayedMemberExceptionSpecs();
>>>
>>> + bool CheckExplicitlyDefaultedComparison(FunctionDecl *MD,
>>> + DefaultedComparisonKind DCK);
>>> +
>>>
>>> //===--------------------------------------------------------------------===//
>>> // C++ Derived Classes
>>> //
>>>
>>> diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
>>> index 80235d8496d2..dae4af8bb249 100644
>>> --- a/clang/lib/AST/Decl.cpp
>>> +++ b/clang/lib/AST/Decl.cpp
>>> @@ -3322,12 +3322,14 @@ bool
>>> FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
>>> return FoundBody;
>>> }
>>>
>>> -SourceRange FunctionDecl::getReturnTypeSourceRange() const {
>>> +FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
>>> const TypeSourceInfo *TSI = getTypeSourceInfo();
>>> - if (!TSI)
>>> - return SourceRange();
>>> - FunctionTypeLoc FTL =
>>> - TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
>>> + return TSI ? TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>()
>>> + : FunctionTypeLoc();
>>> +}
>>> +
>>> +SourceRange FunctionDecl::getReturnTypeSourceRange() const {
>>> + FunctionTypeLoc FTL = getFunctionTypeLoc();
>>> if (!FTL)
>>> return SourceRange();
>>>
>>> @@ -3343,15 +3345,8 @@ SourceRange
>>> FunctionDecl::getReturnTypeSourceRange() const {
>>> }
>>>
>>> SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
>>> - const TypeSourceInfo *TSI = getTypeSourceInfo();
>>> - if (!TSI)
>>> - return SourceRange();
>>> - FunctionTypeLoc FTL =
>>> - TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
>>> - if (!FTL)
>>> - return SourceRange();
>>> -
>>> - return FTL.getExceptionSpecRange();
>>> + FunctionTypeLoc FTL = getFunctionTypeLoc();
>>> + return FTL ? FTL.getExceptionSpecRange() : SourceRange();
>>> }
>>>
>>> /// For an inline function definition in C, or for a gnu_inline function
>>>
>>> diff --git a/clang/lib/Parse/ParseDecl.cpp
>>> b/clang/lib/Parse/ParseDecl.cpp
>>> index b248d7582d84..c41eb74a9cf3 100644
>>> --- a/clang/lib/Parse/ParseDecl.cpp
>>> +++ b/clang/lib/Parse/ParseDecl.cpp
>>> @@ -2349,7 +2349,8 @@ Decl
>>> *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
>>> Diag(ConsumeToken(),
>>> diag::err_default_delete_in_multiple_declaration)
>>> << 0 /* default */;
>>> else
>>> - Diag(ConsumeToken(), diag::err_default_special_members);
>>> + Diag(ConsumeToken(), diag::err_default_special_members)
>>> + << getLangOpts().CPlusPlus2a;
>>> } else {
>>> InitializerScopeRAII InitScope(*this, D, ThisDecl);
>>>
>>>
>>> diff --git a/clang/lib/Parse/ParseDeclCXX.cpp
>>> b/clang/lib/Parse/ParseDeclCXX.cpp
>>> index b98ce3e66292..6d4a1a4a4e87 100644
>>> --- a/clang/lib/Parse/ParseDeclCXX.cpp
>>> +++ b/clang/lib/Parse/ParseDeclCXX.cpp
>>> @@ -2978,7 +2978,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl
>>> *D, bool IsFunction,
>>> Diag(Tok, diag::err_default_delete_in_multiple_declaration)
>>> << 0 /* default */;
>>> else
>>> - Diag(ConsumeToken(), diag::err_default_special_members);
>>> + Diag(ConsumeToken(), diag::err_default_special_members)
>>> + << getLangOpts().CPlusPlus2a;
>>> return ExprError();
>>> }
>>> }
>>>
>>> diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
>>> index 62ec83967bff..6202391ee0b8 100644
>>> --- a/clang/lib/Sema/SemaDecl.cpp
>>> +++ b/clang/lib/Sema/SemaDecl.cpp
>>> @@ -2993,28 +2993,6 @@ struct GNUCompatibleParamWarning {
>>>
>>> } // end anonymous namespace
>>>
>>> -/// getSpecialMember - get the special member enum for a method.
>>> -Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
>>> - if (const CXXConstructorDecl *Ctor =
>>> dyn_cast<CXXConstructorDecl>(MD)) {
>>> - if (Ctor->isDefaultConstructor())
>>> - return Sema::CXXDefaultConstructor;
>>> -
>>> - if (Ctor->isCopyConstructor())
>>> - return Sema::CXXCopyConstructor;
>>> -
>>> - if (Ctor->isMoveConstructor())
>>> - return Sema::CXXMoveConstructor;
>>> - } else if (isa<CXXDestructorDecl>(MD)) {
>>> - return Sema::CXXDestructor;
>>> - } else if (MD->isCopyAssignmentOperator()) {
>>> - return Sema::CXXCopyAssignment;
>>> - } else if (MD->isMoveAssignmentOperator()) {
>>> - return Sema::CXXMoveAssignment;
>>> - }
>>> -
>>> - return Sema::CXXInvalid;
>>> -}
>>> -
>>> // Determine whether the previous declaration was a definition, implicit
>>> // declaration, or a declaration.
>>> template <typename T>
>>>
>>> diff --git a/clang/lib/Sema/SemaDeclCXX.cpp
>>> b/clang/lib/Sema/SemaDeclCXX.cpp
>>> index ff90b9548e29..0201d014e6f2 100644
>>> --- a/clang/lib/Sema/SemaDeclCXX.cpp
>>> +++ b/clang/lib/Sema/SemaDeclCXX.cpp
>>> @@ -6084,6 +6084,67 @@ void Sema::propagateDLLAttrToBaseClassTemplate(
>>> }
>>> }
>>>
>>> +/// Determine the kind of defaulting that would be done for a given
>>> function.
>>> +///
>>> +/// If the function is both a default constructor and a copy / move
>>> constructor
>>> +/// (due to having a default argument for the first parameter), this
>>> picks
>>> +/// CXXDefaultConstructor.
>>> +///
>>> +/// FIXME: Check that case is properly handled by all callers.
>>> +Sema::DefaultedFunctionKind
>>> +Sema::getDefaultedFunctionKind(const FunctionDecl *FD) {
>>> + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
>>> + if (const CXXConstructorDecl *Ctor =
>>> dyn_cast<CXXConstructorDecl>(FD)) {
>>> + if (Ctor->isDefaultConstructor())
>>> + return Sema::CXXDefaultConstructor;
>>> +
>>> + if (Ctor->isCopyConstructor())
>>> + return Sema::CXXCopyConstructor;
>>> +
>>> + if (Ctor->isMoveConstructor())
>>> + return Sema::CXXMoveConstructor;
>>> + }
>>> +
>>> + if (MD->isCopyAssignmentOperator())
>>> + return Sema::CXXCopyAssignment;
>>> +
>>> + if (MD->isMoveAssignmentOperator())
>>> + return Sema::CXXMoveAssignment;
>>> +
>>> + if (isa<CXXDestructorDecl>(FD))
>>> + return Sema::CXXDestructor;
>>> + }
>>> +
>>> + switch (FD->getDeclName().getCXXOverloadedOperator()) {
>>> + case OO_EqualEqual:
>>> + return DefaultedComparisonKind::Equal;
>>> +
>>> + case OO_ExclaimEqual:
>>> + return DefaultedComparisonKind::NotEqual;
>>> +
>>> + case OO_Spaceship:
>>> + // No point allowing this if <=> doesn't exist in the current
>>> language mode.
>>> + if (!getLangOpts().CPlusPlus2a)
>>> + break;
>>> + return DefaultedComparisonKind::ThreeWay;
>>> +
>>> + case OO_Less:
>>> + case OO_LessEqual:
>>> + case OO_Greater:
>>> + case OO_GreaterEqual:
>>> + // No point allowing this if <=> doesn't exist in the current
>>> language mode.
>>> + if (!getLangOpts().CPlusPlus2a)
>>> + break;
>>> + return DefaultedComparisonKind::Relational;
>>> +
>>> + default:
>>> + break;
>>> + }
>>> +
>>> + // Not defaultable.
>>> + return DefaultedFunctionKind();
>>> +}
>>> +
>>> static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
>>> SourceLocation DefaultLoc) {
>>> switch (S.getSpecialMember(MD)) {
>>> @@ -6331,9 +6392,9 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl
>>> *Record) {
>>> Record->setHasTrivialSpecialMemberForCall();
>>>
>>> auto CompleteMemberFunction = [&](CXXMethodDecl *M) {
>>> - // Check whether the explicitly-defaulted special members are valid.
>>> + // Check whether the explicitly-defaulted members are valid.
>>> if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
>>> - CheckExplicitlyDefaultedSpecialMember(M);
>>> + CheckExplicitlyDefaultedFunction(M);
>>>
>>> // For an explicitly defaulted or deleted special member, we defer
>>> // determining triviality until the class is complete. That time is
>>> now!
>>> @@ -6413,6 +6474,15 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl
>>> *Record) {
>>> DiagnoseAbsenceOfOverrideControl(M);
>>> }
>>>
>>> + // Process any defaulted friends in the member-specification.
>>> + if (!Record->isDependentType()) {
>>> + for (FriendDecl *D : Record->friends()) {
>>> + auto *FD = dyn_cast_or_null<FunctionDecl>(D->getFriendDecl());
>>> + if (FD && !FD->isInvalidDecl() && FD->isExplicitlyDefaulted())
>>> + CheckExplicitlyDefaultedFunction(FD);
>>> + }
>>> + }
>>> +
>>> // ms_struct is a request to use the same ABI rules as MSVC. Check
>>> // whether this class uses any C++ features that are implemented
>>> // completely
>>> diff erently in MSVC, and if so, emit a diagnostic.
>>> @@ -6766,9 +6836,22 @@ void
>>> Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
>>> UpdateExceptionSpec(MD->getCanonicalDecl(), ESI);
>>> }
>>>
>>> -void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
>>> +void Sema::CheckExplicitlyDefaultedFunction(FunctionDecl *FD) {
>>> + assert(FD->isExplicitlyDefaulted() && "not explicitly-defaulted");
>>> +
>>> + DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD);
>>> + assert(DefKind && "not a defaultable function");
>>> +
>>> + if (DefKind.isSpecialMember()
>>> + ?
>>> CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD),
>>> +
>>> DefKind.asSpecialMember())
>>> + : CheckExplicitlyDefaultedComparison(FD,
>>> DefKind.asComparison()))
>>> + FD->setInvalidDecl();
>>> +}
>>> +
>>> +bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
>>> + CXXSpecialMember CSM) {
>>> CXXRecordDecl *RD = MD->getParent();
>>> - CXXSpecialMember CSM = getSpecialMember(MD);
>>>
>>> assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
>>> "not an explicitly-defaulted special member");
>>> @@ -6781,7 +6864,7 @@ void
>>> Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
>>>
>>> // C++11 [dcl.fct.def.default]p1:
>>> // A function that is explicitly defaulted shall
>>> - // -- be a special member function (checked elsewhere),
>>> + // -- be a special member function [...] (checked elsewhere),
>>> // -- have the same type (except for ref-qualifiers, and except
>>> that a
>>> // copy operation can take a non-const reference) as an
>>> implicit
>>> // declaration, and
>>> @@ -6960,8 +7043,87 @@ void
>>> Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
>>> }
>>> }
>>>
>>> - if (HadError)
>>> - MD->setInvalidDecl();
>>> + return HadError;
>>> +}
>>> +
>>> +bool Sema::CheckExplicitlyDefaultedComparison(FunctionDecl *FD,
>>> + DefaultedComparisonKind
>>> DCK) {
>>> + assert(DCK != DefaultedComparisonKind::None && "not a defaulted
>>> comparison");
>>> +
>>> + // C++2a [class.compare.default]p1:
>>> + // A defaulted comparison operator function for some class C shall
>>> be a
>>> + // non-template function declared in the member-specification of C
>>> that is
>>> + // -- a non-static const member of C having one parameter of type
>>> + // const C&, or
>>> + // -- a friend of C having two parameters of type const C&.
>>> + CXXRecordDecl *RD =
>>> dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext());
>>> + assert(RD && "defaulted comparison is not defaulted in a class");
>>> +
>>> + QualType ExpectedParmType =
>>> +
>>> Context.getLValueReferenceType(Context.getRecordType(RD).withConst());
>>> + for (const ParmVarDecl *Param : FD->parameters()) {
>>> + if (!Context.hasSameType(Param->getType(), ExpectedParmType)) {
>>> + Diag(FD->getLocation(), diag::err_defaulted_comparison_param)
>>> + << (int)DCK << Param->getType() << ExpectedParmType
>>> + << Param->getSourceRange();
>>> + return true;
>>> + }
>>> + }
>>> +
>>> + // ... non-static const member ...
>>> + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
>>> + assert(!MD->isStatic() && "comparison function cannot be a static
>>> member");
>>> + if (!MD->isConst()) {
>>> + SourceLocation InsertLoc;
>>> + if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc())
>>> + InsertLoc = getLocForEndOfToken(Loc.getRParenLoc());
>>> + Diag(MD->getLocation(), diag::err_defaulted_comparison_non_const)
>>> + << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const");
>>> +
>>> + // Add the 'const' to the type to recover.
>>> + const auto *FPT = MD->getType()->castAs<FunctionProtoType>();
>>> + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
>>> + EPI.TypeQuals.addConst();
>>> + MD->setType(Context.getFunctionType(FPT->getReturnType(),
>>> + FPT->getParamTypes(), EPI));
>>> + }
>>> + } else {
>>> + // A non-member function declared in a class must be a friend.
>>> + assert(FD->getFriendObjectKind() && "expected a friend
>>> declaration");
>>> + }
>>> +
>>> + // C++2a [class.compare.default]p2:
>>> + // A defaulted comparison operator function for class C is defined
>>> as
>>> + // deleted if any non-static data member of C is of reference type
>>> or C is
>>> + // a union-like class.
>>> + // FIXME: Applying this to cases other than == and <=> is
>>> unreasonable.
>>> + // FIXME: Implement.
>>> +
>>> + // C++2a [class.eq]p1, [class.rel]p1:
>>> + // A [defaulted comparison other than <=>] shall have a declared
>>> return
>>> + // type bool.
>>> + if (DCK != DefaultedComparisonKind::ThreeWay &&
>>> + !Context.hasSameType(FD->getDeclaredReturnType(),
>>> Context.BoolTy)) {
>>> + Diag(FD->getLocation(),
>>> diag::err_defaulted_comparison_return_type_not_bool)
>>> + << (int)DCK << FD->getDeclaredReturnType() << Context.BoolTy
>>> + << FD->getReturnTypeSourceRange();
>>> + return true;
>>> + }
>>> +
>>> + // FIXME: Determine whether the function should be defined as deleted.
>>> +
>>> + // C++2a [dcl.fct.def.default]p3:
>>> + // An explicitly-defaulted function [..] may be declared constexpr
>>> or
>>> + // consteval only if it would have been implicitly declared
>>> constexpr.
>>> + // FIXME: There are no rules governing when these should be constexpr,
>>> + // except for the special case of the injected operator==, for which
>>> + // C++2a [class.compare.default]p3 says:
>>> + // The operator is a constexpr function if its definition would
>>> satisfy
>>> + // the requirements for a constexpr function.
>>> + // FIXME: Apply this rule to all defaulted comparisons. The only way
>>> this
>>> + // can fail is if the return type of a defaulted operator<=> is not a
>>> literal
>>> + // type.
>>> + return false;
>>> }
>>>
>>> void Sema::CheckDelayedMemberExceptionSpecs() {
>>> @@ -15006,51 +15168,88 @@ void Sema::SetDeclDeleted(Decl *Dcl,
>>> SourceLocation DelLoc) {
>>> }
>>>
>>> void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
>>> - CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Dcl);
>>> + if (!Dcl || Dcl->isInvalidDecl())
>>> + return;
>>>
>>> - if (MD) {
>>> - if (MD->getParent()->isDependentType()) {
>>> - MD->setDefaulted();
>>> - MD->setExplicitlyDefaulted();
>>> - return;
>>> + auto *FD = dyn_cast<FunctionDecl>(Dcl);
>>> + if (!FD) {
>>> + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(Dcl)) {
>>> + if
>>> (getDefaultedFunctionKind(FTD->getTemplatedDecl()).isComparison()) {
>>> + Diag(DefaultLoc, diag::err_defaulted_comparison_template);
>>> + return;
>>> + }
>>> }
>>>
>>> - CXXSpecialMember Member = getSpecialMember(MD);
>>> - if (Member == CXXInvalid) {
>>> - if (!MD->isInvalidDecl())
>>> - Diag(DefaultLoc, diag::err_default_special_members);
>>> - return;
>>> - }
>>> + Diag(DefaultLoc, diag::err_default_special_members)
>>> + << getLangOpts().CPlusPlus2a;
>>> + return;
>>> + }
>>>
>>> - MD->setDefaulted();
>>> - MD->setExplicitlyDefaulted();
>>> + // Reject if this can't possibly be a defaultable function.
>>> + DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD);
>>> + if (!DefKind &&
>>> + // A dependent function that doesn't locally look defaultable can
>>> + // still instantiate to a defaultable function if it's a
>>> constructor
>>> + // or assignment operator.
>>> + (!FD->isDependentContext() ||
>>> + (!isa<CXXConstructorDecl>(FD) &&
>>> + FD->getDeclName().getCXXOverloadedOperator() != OO_Equal))) {
>>> + Diag(DefaultLoc, diag::err_default_special_members)
>>> + << getLangOpts().CPlusPlus2a;
>>> + return;
>>> + }
>>>
>>> - // Unset that we will have a body for this function. We might not,
>>> - // if it turns out to be trivial, and we don't need this marking now
>>> - // that we've marked it as defaulted.
>>> - MD->setWillHaveBody(false);
>>> + if (DefKind.isComparison() &&
>>> + !isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
>>> + Diag(FD->getLocation(), diag::err_defaulted_comparison_out_of_class)
>>> + << (int)DefKind.asComparison();
>>> + return;
>>> + }
>>>
>>> - // If this definition appears within the record, do the checking
>>> when
>>> - // the record is complete.
>>> - const FunctionDecl *Primary = MD;
>>> - if (const FunctionDecl *Pattern =
>>> MD->getTemplateInstantiationPattern())
>>> - // Ask the template instantiation pattern that actually had the
>>> - // '= default' on it.
>>> - Primary = Pattern;
>>> + // Issue compatibility warning. We already warned if the operator is
>>> + // 'operator<=>' when parsing the '<=>' token.
>>> + if (DefKind.isComparison() &&
>>> + DefKind.asComparison() != DefaultedComparisonKind::ThreeWay) {
>>> + Diag(DefaultLoc, getLangOpts().CPlusPlus2a
>>> + ? diag::warn_cxx17_compat_defaulted_comparison
>>> + : diag::ext_defaulted_comparison);
>>> + }
>>>
>>> - // If the method was defaulted on its first declaration, we will
>>> have
>>> - // already performed the checking in CheckCompletedCXXClass. Such a
>>> - // declaration doesn't trigger an implicit definition.
>>> - if (Primary->getCanonicalDecl()->isDefaulted())
>>> - return;
>>> + FD->setDefaulted();
>>> + FD->setExplicitlyDefaulted();
>>>
>>> - CheckExplicitlyDefaultedSpecialMember(MD);
>>> + // Defer checking functions that are defaulted in a dependent context.
>>> + if (FD->isDependentContext())
>>> + return;
>>>
>>> - if (!MD->isInvalidDecl())
>>> - DefineImplicitSpecialMember(*this, MD, DefaultLoc);
>>> - } else {
>>> - Diag(DefaultLoc, diag::err_default_special_members);
>>> - }
>>> + // Unset that we will have a body for this function. We might not,
>>> + // if it turns out to be trivial, and we don't need this marking now
>>> + // that we've marked it as defaulted.
>>> + FD->setWillHaveBody(false);
>>> +
>>> + // If this definition appears within the record, do the checking when
>>> + // the record is complete. This is always the case for a defaulted
>>> + // comparison.
>>> + if (DefKind.isComparison())
>>> + return;
>>> + auto *MD = cast<CXXMethodDecl>(FD);
>>> +
>>> + const FunctionDecl *Primary = FD;
>>> + if (const FunctionDecl *Pattern =
>>> FD->getTemplateInstantiationPattern())
>>> + // Ask the template instantiation pattern that actually had the
>>> + // '= default' on it.
>>> + Primary = Pattern;
>>> +
>>> + // If the method was defaulted on its first declaration, we will have
>>> + // already performed the checking in CheckCompletedCXXClass. Such a
>>> + // declaration doesn't trigger an implicit definition.
>>> + if (Primary->getCanonicalDecl()->isDefaulted())
>>> + return;
>>> +
>>> + if (CheckExplicitlyDefaultedSpecialMember(MD,
>>> DefKind.asSpecialMember()))
>>> + MD->setInvalidDecl();
>>> + else
>>> + DefineImplicitSpecialMember(*this, MD, DefaultLoc);
>>> }
>>>
>>> static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
>>>
>>> diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
>>> b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
>>> index d1ad304e62e4..31a4302ba826 100644
>>> --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
>>> +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
>>> @@ -2049,6 +2049,11 @@ Decl
>>> *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
>>> }
>>> }
>>>
>>> + if (D->isExplicitlyDefaulted())
>>> + SemaRef.SetDeclDefaulted(Function, D->getLocation());
>>> + if (D->isDeleted())
>>> + SemaRef.SetDeclDeleted(Function, D->getLocation());
>>> +
>>> if (Function->isLocalExternDecl() && !Function->getPreviousDecl())
>>> DC->makeDeclVisibleInContext(PrincipalDecl);
>>>
>>> @@ -2056,7 +2061,6 @@ Decl
>>> *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
>>> PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
>>> PrincipalDecl->setNonMemberOperator();
>>>
>>> - assert(!D->isDefaulted() && "only methods should be defaulted");
>>> return Function;
>>> }
>>>
>>> @@ -4016,9 +4020,6 @@ void Sema::InstantiateExceptionSpec(SourceLocation
>>> PointOfInstantiation,
>>> bool
>>> TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
>>> FunctionDecl *Tmpl)
>>> {
>>> - if (Tmpl->isDeleted())
>>> - New->setDeletedAsWritten();
>>> -
>>> New->setImplicit(Tmpl->isImplicit());
>>>
>>> // Forward the mangling number from the template to the instantiated
>>> decl.
>>>
>>> diff --git
>>> a/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
>>> b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
>>> new file mode 100644
>>> index 000000000000..1f8d6a2a7cff
>>> --- /dev/null
>>> +++ b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
>>> @@ -0,0 +1,46 @@
>>> +// RUN: %clang_cc1 -std=c++2a -verify %s
>>> +
>>> +struct B {};
>>> +bool operator==(const B&, const B&) = default; // expected-error
>>> {{equality comparison operator can only be defaulted in a class definition}}
>>> +bool operator<=>(const B&, const B&) = default; // expected-error
>>> {{three-way comparison operator can only be defaulted in a class
>>> definition}}
>>> +
>>> +template<typename T = void>
>>> + bool operator<(const B&, const B&) = default; // expected-error
>>> {{comparison operator template cannot be defaulted}}
>>> +
>>> +struct A {
>>> + friend bool operator==(const A&, const A&) = default;
>>> + friend bool operator!=(const A&, const B&) = default; //
>>> expected-error {{invalid parameter type for defaulted equality comparison}}
>>> + friend bool operator!=(const B&, const B&) = default; //
>>> expected-error {{invalid parameter type for defaulted equality comparison}}
>>> + friend bool operator<(const A&, const A&);
>>> + friend bool operator<(const B&, const B&) = default; //
>>> expected-error {{invalid parameter type for defaulted relational
>>> comparison}}
>>> + friend bool operator>(A, A) = default; // expected-error {{invalid
>>> parameter type for defaulted relational comparison}}
>>> +
>>> + bool operator<(const A&) const;
>>> + bool operator<=(const A&) const = default;
>>> + bool operator==(const A&) const volatile && = default; //
>>> surprisingly, OK
>>> + bool operator<=>(const A&) = default; // expected-error {{defaulted
>>> member three-way comparison operator must be const-qualified}}
>>> + bool operator>=(const B&) const = default; // expected-error
>>> {{invalid parameter type for defaulted relational comparison}}
>>> + static bool operator>(const B&) = default; // expected-error
>>> {{overloaded 'operator>' cannot be a static member function}}
>>> +
>>> + template<typename T = void>
>>> + friend bool operator==(const A&, const A&) = default; //
>>> expected-error {{comparison operator template cannot be defaulted}}
>>> + template<typename T = void>
>>> + bool operator==(const A&) const = default; // expected-error
>>> {{comparison operator template cannot be defaulted}}
>>> +};
>>> +
>>> +// FIXME: The wording is not clear as to whether these are valid, but
>>> the
>>> +// intention is that they are not.
>>> +bool operator<(const A&, const A&) = default; // expected-error
>>> {{relational comparison operator can only be defaulted in a class
>>> definition}}
>>> +bool A::operator<(const A&) const = default; // expected-error {{can
>>> only be defaulted in a class definition}}
>>> +
>>> +template<typename T> struct Dependent {
>>> + using U = typename T::type;
>>> + bool operator==(U) const = default; // expected-error {{found
>>> 'Dependent<Bad>::U'}}
>>> + friend bool operator==(U, U) = default; // expected-error {{found
>>> 'Dependent<Bad>::U'}}
>>> +};
>>> +
>>> +struct Good { using type = const Dependent<Good>&; };
>>> +template struct Dependent<Good>;
>>> +
>>> +struct Bad { using type = Dependent<Bad>&; };
>>> +template struct Dependent<Bad>; // expected-note {{in instantiation of}}
>>>
>>> diff --git a/clang/test/CXX/class/class.compare/class.eq/p1.cpp
>>> b/clang/test/CXX/class/class.compare/class.eq/p1.cpp
>>> new file mode 100644
>>> index 000000000000..622f66cf9281
>>> --- /dev/null
>>> +++ b/clang/test/CXX/class/class.compare/class.eq/p1.cpp
>>> @@ -0,0 +1,25 @@
>>> +// RUN: %clang_cc1 -std=c++2a -verify %s
>>> +
>>> +struct Good {
>>> + bool operator==(const Good&) const = default;
>>> + bool operator!=(const Good&) const = default;
>>> + friend bool operator==(const Good&, const Good&) = default;
>>> + friend bool operator!=(const Good&, const Good&) = default;
>>> +};
>>> +
>>> +enum Bool : bool {};
>>> +struct Bad {
>>> + bool &operator==(const Bad&) const = default; // expected-error
>>> {{return type for defaulted equality comparison operator must be 'bool',
>>> not 'bool &'}}
>>> + const bool operator!=(const Bad&) const = default; // expected-error
>>> {{return type for defaulted equality comparison operator must be 'bool',
>>> not 'const bool'}}
>>> + friend Bool operator==(const Bad&, const Bad&) = default; //
>>> expected-error {{return type for defaulted equality comparison operator
>>> must be 'bool', not 'Bool'}}
>>> + friend int operator!=(const Bad&, const Bad&) = default; //
>>> expected-error {{return type for defaulted equality comparison operator
>>> must be 'bool', not 'int'}}
>>> +};
>>> +
>>> +template<typename T> struct Ugly {
>>> + T operator==(const Ugly&) const = default; // expected-error {{return
>>> type}}
>>> + T operator!=(const Ugly&) const = default; // expected-error {{return
>>> type}}
>>> + friend T operator==(const Ugly&, const Ugly&) = default; //
>>> expected-error {{return type}}
>>> + friend T operator!=(const Ugly&, const Ugly&) = default; //
>>> expected-error {{return type}}
>>> +};
>>> +template struct Ugly<bool>;
>>> +template struct Ugly<int>; // expected-note {{in instantiation of}}
>>>
>>> diff --git a/clang/test/CXX/class/class.compare/class.rel/p1.cpp
>>> b/clang/test/CXX/class/class.compare/class.rel/p1.cpp
>>> new file mode 100644
>>> index 000000000000..3797d5f81f56
>>> --- /dev/null
>>> +++ b/clang/test/CXX/class/class.compare/class.rel/p1.cpp
>>> @@ -0,0 +1,25 @@
>>> +// RUN: %clang_cc1 -std=c++2a -verify %s
>>> +
>>> +struct Good {
>>> + bool operator<(const Good&) const = default;
>>> + bool operator>(const Good&) const = default;
>>> + friend bool operator<=(const Good&, const Good&) = default;
>>> + friend bool operator>=(const Good&, const Good&) = default;
>>> +};
>>> +
>>> +enum Bool : bool {};
>>> +struct Bad {
>>> + bool &operator<(const Bad&) const = default; // expected-error
>>> {{return type for defaulted relational comparison operator must be 'bool',
>>> not 'bool &'}}
>>> + const bool operator>(const Bad&) const = default; // expected-error
>>> {{return type for defaulted relational comparison operator must be 'bool',
>>> not 'const bool'}}
>>> + friend Bool operator<=(const Bad&, const Bad&) = default; //
>>> expected-error {{return type for defaulted relational comparison operator
>>> must be 'bool', not 'Bool'}}
>>> + friend int operator>=(const Bad&, const Bad&) = default; //
>>> expected-error {{return type for defaulted relational comparison operator
>>> must be 'bool', not 'int'}}
>>> +};
>>> +
>>> +template<typename T> struct Ugly {
>>> + T operator<(const Ugly&) const = default; // expected-error {{return
>>> type}}
>>> + T operator>(const Ugly&) const = default; // expected-error {{return
>>> type}}
>>> + friend T operator<=(const Ugly&, const Ugly&) = default; //
>>> expected-error {{return type}}
>>> + friend T operator>=(const Ugly&, const Ugly&) = default; //
>>> expected-error {{return type}}
>>> +};
>>> +template struct Ugly<bool>;
>>> +template struct Ugly<int>; // expected-note {{in instantiation of}}
>>>
>>> diff --git
>>> a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
>>> b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
>>> index 3f2bc569edf6..6e9b45903d39 100644
>>> --- a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
>>> +++ b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
>>> @@ -1,12 +1,28 @@
>>> -// RUN: %clang_cc1 -verify %s -std=c++11
>>> -// RUN: %clang_cc1 -verify %s -std=c++17
>>> -// RUN: %clang_cc1 -verify %s -std=c++2a
>>> +// RUN: %clang_cc1 -verify=expected,pre2a %s -std=c++11
>>> +// RUN: %clang_cc1 -verify=expected,pre2a %s -std=c++17
>>> +// RUN: %clang_cc1 -verify=expected %s -std=c++2a
>>>
>>> // A function that is explicitly defaulted shall
>>> struct A {
>>> - // -- be a special member function,
>>> - A(int) = default; // expected-error {{only special member functions
>>> may be defaulted}}
>>> + // -- be a special member function [C++2a: or a comparison operator
>>> function],
>>> + A(int) = default;
>>> +#if __cplusplus <= 201703L
>>> + // expected-error at -2 {{only special member functions may be
>>> defaulted}}
>>> +#else
>>> + // expected-error at -4 {{only special member functions and comparison
>>> operators may be defaulted}}
>>> +#endif
>>> A(A) = default; // expected-error {{must pass its first argument by
>>> reference}}
>>> + void f(A) = default; // expected-error-re {{only special member
>>> functions{{( and comparison operators)?}} may be defaulted}}
>>> +
>>> + bool operator==(const A&) const = default; // pre2a-warning
>>> {{defaulted comparison operators are a C++20 extension}}
>>> + bool operator!=(const A&) const = default; // pre2a-warning
>>> {{defaulted comparison operators are a C++20 extension}}
>>> + bool operator<(const A&) const = default; // pre2a-error {{only
>>> special member functions may be defaulted}}
>>> + bool operator>(const A&) const = default; // pre2a-error {{only
>>> special member functions may be defaulted}}
>>> + bool operator<=(const A&) const = default; // pre2a-error {{only
>>> special member functions may be defaulted}}
>>> + bool operator>=(const A&) const = default; // pre2a-error {{only
>>> special member functions may be defaulted}}
>>> + bool operator<=>(const A&) const = default; // pre2a-error 1+{{}}
>>> pre2a-warning {{'<=>' is a single token in C++2a}}
>>> +
>>> + A operator+(const A&) const = default; // expected-error-re {{only
>>> special member functions{{( and comparison operators)?}} may be defaulted}}
>>>
>>> // -- have the same declared function type as if it had been
>>> implicitly
>>> // declared
>>>
>>> diff --git a/clang/test/Parser/cxx0x-decl.cpp
>>> b/clang/test/Parser/cxx0x-decl.cpp
>>> index 2f219ac87fb8..3c1c3602691b 100644
>>> --- a/clang/test/Parser/cxx0x-decl.cpp
>>> +++ b/clang/test/Parser/cxx0x-decl.cpp
>>> @@ -39,7 +39,7 @@ static_assert(something, ""); // expected-error
>>> {{undeclared identifier}}
>>>
>>> // PR9903
>>> struct SS {
>>> - typedef void d() = default; // expected-error {{function definition
>>> declared 'typedef'}} expected-error {{only special member functions may be
>>> defaulted}}
>>> + typedef void d() = default; // expected-error {{function definition
>>> declared 'typedef'}} expected-error {{only special member functions and
>>> comparison operators may be defaulted}}
>>> };
>>>
>>> using PR14855 = int S::; // expected-error {{expected ';' after alias
>>> declaration}}
>>>
>>> diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
>>> b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
>>> index 45a65440d599..c68b7d67932e 100644
>>> --- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
>>> +++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
>>> @@ -175,7 +175,7 @@ namespace PR14577 {
>>> Outer<T>::Inner1<T>::~Inner1() = delete; // expected-error {{nested
>>> name specifier 'Outer<T>::Inner1<T>::' for declaration does not refer into
>>> a class, class template or class template partial specialization}}
>>> expected-error {{only functions can have deleted definitions}}
>>>
>>> template<typename T>
>>> - Outer<T>::Inner2<T>::~Inner2() = default; // expected-error {{nested
>>> name specifier 'Outer<T>::Inner2<T>::' for declaration does not refer into
>>> a class, class template or class template partial specialization}}
>>> expected-error {{only special member functions may be defaulted}}
>>> + Outer<T>::Inner2<T>::~Inner2() = default; // expected-error {{nested
>>> name specifier 'Outer<T>::Inner2<T>::' for declaration does not refer into
>>> a class, class template or class template partial specialization}}
>>> }
>>>
>>> extern "C" { // expected-note {{extern "C" language linkage
>>> specification begins here}}
>>>
>>> diff --git a/clang/test/SemaCXX/cxx17-compat.cpp
>>> b/clang/test/SemaCXX/cxx17-compat.cpp
>>> index 3d5420fa0637..e063b1fc1807 100644
>>> --- a/clang/test/SemaCXX/cxx17-compat.cpp
>>> +++ b/clang/test/SemaCXX/cxx17-compat.cpp
>>> @@ -88,3 +88,36 @@ void f() {
>>> // expected-warning at -4 {{decomposition declaration declared with
>>> 'static thread_local' specifiers is incompatible with C++ standards before
>>> C++2a}}
>>> #endif
>>> }
>>> +
>>> +struct DefaultedComparisons {
>>> + bool operator==(const DefaultedComparisons&) const = default;
>>> + bool operator!=(const DefaultedComparisons&) const = default;
>>> +#if __cplusplus <= 201703L
>>> + // expected-warning at -3 {{defaulted comparison operators are a C++20
>>> extension}}
>>> + // expected-warning at -3 {{defaulted comparison operators are a C++20
>>> extension}}
>>> +#else
>>> + // expected-warning at -6 {{defaulted comparison operators are
>>> incompatible with C++ standards before C++20}}
>>> + // expected-warning at -6 {{defaulted comparison operators are
>>> incompatible with C++ standards before C++20}}
>>> +#endif
>>> + bool operator<=>(const DefaultedComparisons&) const = default;
>>> +#if __cplusplus <= 201703L
>>> + // expected-error at -2 {{'operator<=' cannot be the name of a variable
>>> or data member}} expected-error at -2 0+{{}} expected-warning at -2 {{}}
>>> +#else
>>> + // expected-warning at -4 {{'<=>' operator is incompatible with C++
>>> standards before C++2a}}
>>> +#endif
>>> + bool operator<(const DefaultedComparisons&) const = default;
>>> + bool operator<=(const DefaultedComparisons&) const = default;
>>> + bool operator>(const DefaultedComparisons&) const = default;
>>> + bool operator>=(const DefaultedComparisons&) const = default;
>>> +#if __cplusplus <= 201703L
>>> + // expected-error at -5 {{only special member functions}}
>>> + // expected-error at -5 {{only special member functions}}
>>> + // expected-error at -5 {{only special member functions}}
>>> + // expected-error at -5 {{only special member functions}}
>>> +#else
>>> + // expected-warning at -10 {{defaulted comparison operators are
>>> incompatible with C++ standards before C++20}}
>>> + // expected-warning at -10 {{defaulted comparison operators are
>>> incompatible with C++ standards before C++20}}
>>> + // expected-warning at -10 {{defaulted comparison operators are
>>> incompatible with C++ standards before C++20}}
>>> + // expected-warning at -10 {{defaulted comparison operators are
>>> incompatible with C++ standards before C++20}}
>>> +#endif
>>> +};
>>>
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at lists.llvm.org
>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200310/67d0b8c4/attachment-0001.html>
More information about the cfe-commits
mailing list