summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard@metafoo.co.uk>2019-12-10 16:45:02 -0800
committerRichard Smith <richard@metafoo.co.uk>2019-12-10 17:24:27 -0800
commitbc24014b9765a454cb5214f4871451a41ffb7d29 (patch)
tree8824f31e7dc574ce2a567dcfedc2f259c2a3fa6f /clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
parentf364686f34d80e0873b478933952c6b664177ce4 (diff)
downloadbcm5719-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.cpp87
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.
///
OpenPOWER on IntegriCloud