diff options
author | Richard Smith <richard@metafoo.co.uk> | 2019-12-10 16:45:02 -0800 |
---|---|---|
committer | Richard Smith <richard@metafoo.co.uk> | 2019-12-10 17:24:27 -0800 |
commit | bc24014b9765a454cb5214f4871451a41ffb7d29 (patch) | |
tree | 8824f31e7dc574ce2a567dcfedc2f259c2a3fa6f /clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | |
parent | f364686f34d80e0873b478933952c6b664177ce4 (diff) | |
download | bcm5719-llvm-bc24014b9765a454cb5214f4871451a41ffb7d29.tar.gz bcm5719-llvm-bc24014b9765a454cb5214f4871451a41ffb7d29.zip |
[c++20] Implement P1185R2 (as modified by P2002R0).
For each defaulted operator<=> in a class that doesn't explicitly
declare any operator==, also inject a matching implicit defaulted
operator==.
Diffstat (limited to 'clang/lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 87 |
1 files changed, 81 insertions, 6 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 71399ff3590..0bff0747df3 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1794,8 +1794,9 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context, /// 1) instantiating function templates /// 2) substituting friend declarations /// 3) substituting deduction guide declarations for nested class templates -Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, - TemplateParameterList *TemplateParams) { +Decl *TemplateDeclInstantiator::VisitFunctionDecl( + FunctionDecl *D, TemplateParameterList *TemplateParams, + RewriteKind FunctionRewriteKind) { // Check whether there is already a function template specialization for // this declaration. FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); @@ -1865,6 +1866,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); + if (FunctionRewriteKind != RewriteKind::None) + adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo); + FunctionDecl *Function; if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) { Function = CXXDeductionGuideDecl::Create( @@ -2101,8 +2105,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( CXXMethodDecl *D, TemplateParameterList *TemplateParams, - Optional<const ASTTemplateArgumentListInfo *> - ClassScopeSpecializationArgs) { + Optional<const ASTTemplateArgumentListInfo *> ClassScopeSpecializationArgs, + RewriteKind FunctionRewriteKind) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { // We are creating a function template specialization from a function @@ -2181,13 +2185,17 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( if (!DC) return nullptr; } + DeclarationNameInfo NameInfo + = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); + + if (FunctionRewriteKind != RewriteKind::None) + adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo); + // Build the instantiated method declaration. CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); CXXMethodDecl *Method = nullptr; SourceLocation StartLoc = D->getInnerLocStart(); - DeclarationNameInfo NameInfo - = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { Method = CXXConstructorDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -3523,6 +3531,73 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, return SubstD; } +void TemplateDeclInstantiator::adjustForRewrite(RewriteKind RK, + FunctionDecl *Orig, QualType &T, + TypeSourceInfo *&TInfo, + DeclarationNameInfo &NameInfo) { + assert(RK == RewriteKind::RewriteSpaceshipAsEqualEqual); + + // C++2a [class.compare.default]p3: + // the return type is replaced with bool + auto *FPT = T->castAs<FunctionProtoType>(); + T = SemaRef.Context.getFunctionType( + SemaRef.Context.BoolTy, FPT->getParamTypes(), FPT->getExtProtoInfo()); + + // Update the return type in the source info too. The most straightforward + // way is to create new TypeSourceInfo for the new type. Use the location of + // the '= default' as the location of the new type. + // + // FIXME: Set the correct return type when we initially transform the type, + // rather than delaying it to now. + TypeSourceInfo *NewTInfo = + SemaRef.Context.getTrivialTypeSourceInfo(T, Orig->getEndLoc()); + auto OldLoc = TInfo->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>(); + assert(OldLoc && "type of function is not a function type?"); + auto NewLoc = NewTInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>(); + for (unsigned I = 0, N = OldLoc.getNumParams(); I != N; ++I) + NewLoc.setParam(I, OldLoc.getParam(I)); + TInfo = NewTInfo; + + // and the declarator-id is replaced with operator== + NameInfo.setName( + SemaRef.Context.DeclarationNames.getCXXOperatorName(OO_EqualEqual)); +} + +FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, + FunctionDecl *Spaceship) { + if (Spaceship->isInvalidDecl()) + return nullptr; + + // C++2a [class.compare.default]p3: + // an == operator function is declared implicitly [...] with the same + // access and function-definition and in the same class scope as the + // three-way comparison operator function + MultiLevelTemplateArgumentList NoTemplateArgs; + TemplateDeclInstantiator Instantiator(*this, RD, NoTemplateArgs); + Decl *R; + if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) { + R = Instantiator.VisitCXXMethodDecl( + MD, nullptr, None, + TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); + } else { + assert(Spaceship->getFriendObjectKind() && + "defaulted spaceship is neither a member nor a friend"); + + R = Instantiator.VisitFunctionDecl( + Spaceship, nullptr, + TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); + if (!R) + return nullptr; + + FriendDecl *FD = + FriendDecl::Create(Context, RD, Spaceship->getLocation(), + cast<NamedDecl>(R), Spaceship->getBeginLoc()); + FD->setAccess(AS_public); + RD->addDecl(FD); + } + return cast_or_null<FunctionDecl>(R); +} + /// Instantiates a nested template parameter list in the current /// instantiation context. /// |