Should be fixed in llvmorg-11-init-5426-g4cba668ac13. 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