On Tue, Mar 10, 2020 at 7:35 PM Richard Smith <rich...@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@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@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@-2 {{only special member functions may be >>> defaulted}} >>> +#else >>> + // expected-error@-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@-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@-3 {{defaulted comparison operators are a C++20 >>> extension}} >>> + // expected-warning@-3 {{defaulted comparison operators are a C++20 >>> extension}} >>> +#else >>> + // expected-warning@-6 {{defaulted comparison operators are >>> incompatible with C++ standards before C++20}} >>> + // expected-warning@-6 {{defaulted comparison operators are >>> incompatible with C++ standards before C++20}} >>> +#endif >>> + bool operator<=>(const DefaultedComparisons&) const = default; >>> +#if __cplusplus <= 201703L >>> + // expected-error@-2 {{'operator<=' cannot be the name of a variable >>> or data member}} expected-error@-2 0+{{}} expected-warning@-2 {{}} >>> +#else >>> + // expected-warning@-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@-5 {{only special member functions}} >>> + // expected-error@-5 {{only special member functions}} >>> + // expected-error@-5 {{only special member functions}} >>> + // expected-error@-5 {{only special member functions}} >>> +#else >>> + // expected-warning@-10 {{defaulted comparison operators are >>> incompatible with C++ standards before C++20}} >>> + // expected-warning@-10 {{defaulted comparison operators are >>> incompatible with C++ standards before C++20}} >>> + // expected-warning@-10 {{defaulted comparison operators are >>> incompatible with C++ standards before C++20}} >>> + // expected-warning@-10 {{defaulted comparison operators are >>> incompatible with C++ standards before C++20}} >>> +#endif >>> +}; >>> >>> >>> >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits@lists.llvm.org >>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >>> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits