summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h23
-rw-r--r--include/clang/AST/DeclCXX.h90
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h7
-rw-r--r--include/clang/Basic/DeclNodes.td1
-rw-r--r--include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--lib/AST/DeclBase.cpp1
-rw-r--r--lib/AST/DeclCXX.cpp17
-rw-r--r--lib/CodeGen/CGDecl.cpp1
-rw-r--r--lib/Sema/SemaDecl.cpp22
-rw-r--r--lib/Sema/SemaDeclCXX.cpp7
-rw-r--r--lib/Sema/SemaExpr.cpp3
-rw-r--r--lib/Sema/SemaInit.cpp21
-rw-r--r--lib/Sema/SemaOverload.cpp10
-rw-r--r--lib/Sema/SemaTemplate.cpp29
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp6
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp33
-rw-r--r--lib/Serialization/ASTCommon.cpp1
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp8
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp6
-rw-r--r--tools/libclang/CIndex.cpp1
20 files changed, 202 insertions, 87 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 51f72736e9..cd6b8f7421 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1608,7 +1608,11 @@ private:
unsigned SClass : 2;
unsigned IsInline : 1;
unsigned IsInlineSpecified : 1;
+protected:
+ // This is shared by CXXConstructorDecl, CXXConversionDecl, and
+ // CXXDeductionGuideDecl.
unsigned IsExplicitSpecified : 1;
+private:
unsigned IsVirtualAsWritten : 1;
unsigned IsPure : 1;
unsigned HasInheritedPrototype : 1;
@@ -1855,19 +1859,6 @@ public:
bool isVirtualAsWritten() const { return IsVirtualAsWritten; }
void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; }
- /// Whether this function is marked as explicit explicitly.
- bool isExplicitSpecified() const { return IsExplicitSpecified; }
- void setExplicitSpecified() {
- assert((getKind() == CXXConstructor || getKind() == CXXConversion ||
- isDeductionGuide()) && "cannot be explicit");
- IsExplicitSpecified = true;
- }
-
- /// Whether this function is explicit.
- bool isExplicit() const {
- return getFirstDecl()->isExplicitSpecified();
- }
-
/// Whether this virtual function is pure, i.e. makes the containing class
/// abstract.
bool isPure() const { return IsPure; }
@@ -1946,12 +1937,6 @@ public:
bool isDeletedAsWritten() const { return IsDeleted && !IsDefaulted; }
void setDeletedAsWritten(bool D = true) { IsDeleted = D; }
- /// \brief Determines whether this function is a deduction guide.
- bool isDeductionGuide() const {
- return getDeclName().getNameKind() ==
- DeclarationName::CXXDeductionGuideName;
- }
-
/// \brief Determines whether this function is "main", which is the
/// entry point into an executable program.
bool isMain() const;
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 020ebfb4af..7267afdc7f 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1738,6 +1738,58 @@ public:
friend class ASTWriter;
};
+/// \brief Represents a C++ deduction guide declaration.
+///
+/// \code
+/// template<typename T> struct A { A(); A(T); };
+/// A() -> A<int>;
+/// \endcode
+///
+/// In this example, there will be an explicit deduction guide from the
+/// second line, and implicit deduction guide templates synthesized from
+/// the constructors of \c A.
+class CXXDeductionGuideDecl : public FunctionDecl {
+ void anchor() override;
+private:
+ CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+ bool IsExplicit, const DeclarationNameInfo &NameInfo,
+ QualType T, TypeSourceInfo *TInfo,
+ SourceLocation EndLocation)
+ : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
+ SC_None, false, false) {
+ if (EndLocation.isValid())
+ setRangeEnd(EndLocation);
+ IsExplicitSpecified = IsExplicit;
+ }
+
+public:
+ static CXXDeductionGuideDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, bool IsExplicit,
+ const DeclarationNameInfo &NameInfo,
+ QualType T, TypeSourceInfo *TInfo,
+ SourceLocation EndLocation);
+
+ static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ /// Whether this deduction guide is explicit.
+ bool isExplicit() const { return IsExplicitSpecified; }
+
+ /// Whether this deduction guide was declared with the 'explicit' specifier.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
+ /// Get the template for which this guide performs deduction.
+ TemplateDecl *getDeducedTemplate() const {
+ return getDeclName().getCXXDeductionGuideTemplate();
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == CXXDeductionGuide; }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
/// \brief Represents a static or instance method of a struct/union/class.
///
/// In the terminology of the C++ Standard, these are the (static and
@@ -2181,8 +2233,7 @@ class CXXConstructorDecl final
setImplicit(isImplicitlyDeclared);
if (Inherited)
*getTrailingObjects<InheritedConstructor>() = Inherited;
- if (isExplicitSpecified)
- setExplicitSpecified();
+ IsExplicitSpecified = isExplicitSpecified;
}
public:
@@ -2258,6 +2309,14 @@ public:
CtorInitializers = Initializers;
}
+ /// Whether this function is marked as explicit explicitly.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
+ /// Whether this function is explicit.
+ bool isExplicit() const {
+ return getCanonicalDecl()->isExplicitSpecified();
+ }
+
/// \brief Determine whether this constructor is a delegating constructor.
bool isDelegatingConstructor() const {
return (getNumCtorInitializers() == 1) &&
@@ -2393,7 +2452,14 @@ public:
void setOperatorDelete(FunctionDecl *OD);
const FunctionDecl *getOperatorDelete() const {
- return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete;
+ return getCanonicalDecl()->OperatorDelete;
+ }
+
+ CXXDestructorDecl *getCanonicalDecl() override {
+ return cast<CXXDestructorDecl>(FunctionDecl::getCanonicalDecl());
+ }
+ const CXXDestructorDecl *getCanonicalDecl() const {
+ return const_cast<CXXDestructorDecl*>(this)->getCanonicalDecl();
}
// Implement isa/cast/dyncast/etc.
@@ -2424,8 +2490,7 @@ class CXXConversionDecl : public CXXMethodDecl {
SourceLocation EndLocation)
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, isConstexpr, EndLocation) {
- if (isExplicitSpecified)
- setExplicitSpecified();
+ IsExplicitSpecified = isExplicitSpecified;
}
public:
@@ -2438,6 +2503,14 @@ public:
SourceLocation EndLocation);
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+ /// Whether this function is marked as explicit explicitly.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
+ /// Whether this function is explicit.
+ bool isExplicit() const {
+ return getCanonicalDecl()->isExplicitSpecified();
+ }
+
/// \brief Returns the type that this conversion function is converting to.
QualType getConversionType() const {
return getType()->getAs<FunctionType>()->getReturnType();
@@ -2447,6 +2520,13 @@ public:
/// a lambda closure type to a block pointer.
bool isLambdaToBlockPointerConversion() const;
+ CXXConversionDecl *getCanonicalDecl() override {
+ return cast<CXXConversionDecl>(FunctionDecl::getCanonicalDecl());
+ }
+ const CXXConversionDecl *getCanonicalDecl() const {
+ return const_cast<CXXConversionDecl*>(this)->getCanonicalDecl();
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == CXXConversion; }
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index f41f841626..d75b2c455c 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1946,6 +1946,13 @@ DEF_TRAVERSE_DECL(FunctionDecl, {
ReturnValue = TraverseFunctionHelper(D);
})
+DEF_TRAVERSE_DECL(CXXDeductionGuideDecl, {
+ // We skip decls_begin/decls_end, which are already covered by
+ // TraverseFunctionHelper().
+ ShouldVisitChildren = false;
+ ReturnValue = TraverseFunctionHelper(D);
+})
+
DEF_TRAVERSE_DECL(CXXMethodDecl, {
// We skip decls_begin/decls_end, which are already covered by
// TraverseFunctionHelper().
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index 7b581d3eec..3298a80e51 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -45,6 +45,7 @@ def Named : Decl<1>;
def ObjCAtDefsField : DDecl<Field>;
def MSProperty : DDecl<Declarator>;
def Function : DDecl<Declarator>, DeclContext;
+ def CXXDeductionGuide : DDecl<Function>;
def CXXMethod : DDecl<Function>;
def CXXConstructor : DDecl<CXXMethod>;
def CXXDestructor : DDecl<CXXMethod>;
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index c361e80fcd..91e5734451 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -1123,6 +1123,8 @@ namespace clang {
DECL_EXPORT,
/// \brief A CXXRecordDecl record.
DECL_CXX_RECORD,
+ /// \brief A CXXDeductionGuideDecl record.
+ DECL_CXX_DEDUCTION_GUIDE,
/// \brief A CXXMethodDecl record.
DECL_CXX_METHOD,
/// \brief A CXXConstructorDecl record.
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 6111abab64..cda70c5edc 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -619,6 +619,7 @@ bool Decl::isWeakImported() const {
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
case Function:
+ case CXXDeductionGuide:
case CXXMethod:
case CXXConstructor:
case ConstructorUsingShadow:
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a9db65a515..fdfd6c0705 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1472,6 +1472,23 @@ bool CXXRecordDecl::mayBeAbstract() const {
return false;
}
+void CXXDeductionGuideDecl::anchor() { }
+
+CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
+ ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit,
+ const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+ SourceLocation EndLocation) {
+ return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, IsExplicit,
+ NameInfo, T, TInfo, EndLocation);
+}
+
+CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID) CXXDeductionGuideDecl(C, nullptr, SourceLocation(), false,
+ DeclarationNameInfo(), QualType(),
+ nullptr, SourceLocation());
+}
+
void CXXMethodDecl::anchor() { }
bool CXXMethodDecl::isStatic() const {
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index b7c1743f62..4ee8b98e67 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -50,6 +50,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::TemplateTypeParm:
case Decl::UnresolvedUsingValue:
case Decl::NonTypeTemplateParm:
+ case Decl::CXXDeductionGuide:
case Decl::CXXMethod:
case Decl::CXXConstructor:
case Decl::CXXDestructor:
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 3905348d3c..77d7498302 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -7658,14 +7658,9 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
- // We don't need to store much extra information for a deduction guide, so
- // just model it as a plain FunctionDecl.
- auto *FD = FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(),
- NameInfo, R, TInfo, SC, isInline,
- true /*HasPrototype*/, isConstexpr);
- if (isExplicit)
- FD->setExplicitSpecified();
- return FD;
+ return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getLocStart(),
+ isExplicit, NameInfo, R, TInfo,
+ D.getLocEnd());
} else if (DC->isRecord()) {
// If the name of the function is the same as the name of the record,
// then this must be an invalid constructor that has a return type.
@@ -8154,7 +8149,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// The explicit specifier shall be used only in the declaration of a
// constructor or conversion function within its class definition;
// see 12.3.1 and 12.3.2.
- if (isExplicit && !NewFD->isInvalidDecl() && !NewFD->isDeductionGuide()) {
+ if (isExplicit && !NewFD->isInvalidDecl() &&
+ !isa<CXXDeductionGuideDecl>(NewFD)) {
if (!CurContext->isRecord()) {
// 'explicit' was specified outside of the class.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
@@ -9152,14 +9148,14 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(NewFD)) {
ActOnConversionDeclarator(Conversion);
- } else if (NewFD->isDeductionGuide()) {
- if (auto *TD = NewFD->getDescribedFunctionTemplate())
+ } else if (auto *Guide = dyn_cast<CXXDeductionGuideDecl>(NewFD)) {
+ if (auto *TD = Guide->getDescribedFunctionTemplate())
CheckDeductionGuideTemplate(TD);
// A deduction guide is not on the list of entities that can be
// explicitly specialized.
- if (NewFD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- Diag(NewFD->getLocStart(), diag::err_deduction_guide_specialized)
+ if (Guide->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ Diag(Guide->getLocStart(), diag::err_deduction_guide_specialized)
<< /*explicit specialization*/ 1;
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 6887962940..d28354f6e8 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -650,10 +650,11 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// FIXME: It's not clear what should happen if multiple declarations of a
// deduction guide have different explicitness. For now at least we simply
// reject any case where the explicitness changes.
- if (New->isDeductionGuide() &&
- New->isExplicitSpecified() != Old->isExplicitSpecified()) {
+ auto *NewGuide = dyn_cast<CXXDeductionGuideDecl>(New);
+ if (NewGuide && NewGuide->isExplicitSpecified() !=
+ cast<CXXDeductionGuideDecl>(Old)->isExplicitSpecified()) {
Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch)
- << New->isExplicitSpecified();
+ << NewGuide->isExplicitSpecified();
Diag(Old->getLocation(), diag::note_previous_declaration);
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e76a8b6da0..d628b9898a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3036,6 +3036,9 @@ ExprResult Sema::BuildDeclarationNameExpr(
break;
}
+ case Decl::CXXDeductionGuide:
+ llvm_unreachable("building reference to deduction guide");
+
case Decl::MSProperty:
valueKind = VK_LValue;
break;
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 151b974b41..6d20b01e4e 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -8296,10 +8296,10 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
if (D->isInvalidDecl())
continue;
- FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(D);
- FunctionDecl *FD =
- TD ? TD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D);
- if (!FD)
+ auto *TD = dyn_cast<FunctionTemplateDecl>(D);
+ auto *GD = dyn_cast_or_null<CXXDeductionGuideDecl>(
+ TD ? TD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D));
+ if (!GD)
continue;
// C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
@@ -8309,21 +8309,21 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// The converting constructors of T are candidate functions.
if (Kind.isCopyInit() && !ListInit) {
// Only consider converting constructors.
- if (FD->isExplicit())
+ if (GD->isExplicit())
continue;
// When looking for a converting constructor, deduction guides that
// could never be called with one argument are not interesting to
// check or note.
- if (FD->getMinRequiredArguments() > 1 ||
- (FD->getNumParams() == 0 && !FD->isVariadic()))
+ if (GD->getMinRequiredArguments() > 1 ||
+ (GD->getNumParams() == 0 && !GD->isVariadic()))
continue;
}
// C++ [over.match.list]p1.1: (first phase list initialization)
// Initially, the candidate functions are the initializer-list
// constructors of the class T
- if (OnlyListConstructors && !isInitListConstructor(FD))
+ if (OnlyListConstructors && !isInitListConstructor(GD))
continue;
// C++ [over.match.list]p1.2: (second phase list initialization)
@@ -8345,7 +8345,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
Inits, Candidates,
SuppressUserConversions);
else
- AddOverloadCandidate(FD, I.getPair(), Inits, Candidates,
+ AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
SuppressUserConversions);
}
return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
@@ -8416,7 +8416,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// C++ [over.match.list]p1:
// In copy-list-initialization, if an explicit constructor is chosen, the
// initialization is ill-formed.
- if (Kind.isCopyInit() && ListInit && Best->Function->isExplicit()) {
+ if (Kind.isCopyInit() && ListInit &&
+ cast<CXXDeductionGuideDecl>(Best->Function)->isExplicit()) {
bool IsDeductionGuide = !Best->Function->isImplicit();
Diag(Kind.getLocation(), diag::err_deduced_class_template_explicit)
<< TemplateName << IsDeductionGuide;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 659d6226f3..32a03a57ca 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -8992,12 +8992,10 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
}
// -- F1 is generated from a deduction-guide and F2 is not
- if (Cand1.Function && Cand2.Function && Cand1.Function->isDeductionGuide() &&
- Cand1.Function->isImplicit() != Cand2.Function->isImplicit()) {
- assert(Cand2.Function->isDeductionGuide() &&
- "comparing deduction guide with non-deduction-guide");
- return Cand2.Function->isImplicit();
- }
+ auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
+ auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function);
+ if (Guide1 && Guide2 && Guide1->isImplicit() != Guide2->isImplicit())
+ return Guide2->isImplicit();
// -- F1 is a non-template function and F2 is a function template
// specialization, or, if not that,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 4c5f3bee15..e05f3fe36d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1438,7 +1438,8 @@ struct ConvertConstructorToDeductionGuideTransform {
unsigned Depth1IndexAdjustment = Template->getTemplateParameters()->size();
/// Transform a constructor declaration into a deduction guide.
- NamedDecl *transformConstructor(FunctionTemplateDecl *FTD, FunctionDecl *FD) {
+ NamedDecl *transformConstructor(FunctionTemplateDecl *FTD,
+ CXXConstructorDecl *CD) {
SmallVector<TemplateArgument, 16> SubstArgs;
// C++ [over.match.class.deduct]p1:
@@ -1485,7 +1486,7 @@ struct ConvertConstructorToDeductionGuideTransform {
Args.addOuterTemplateArguments(None);
}
- FunctionProtoTypeLoc FPTL = FD->getTypeSourceInfo()->getTypeLoc()
+ FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
.getAsAdjusted<FunctionProtoTypeLoc>();
assert(FPTL && "no prototype for constructor declaration");
@@ -1499,9 +1500,9 @@ struct ConvertConstructorToDeductionGuideTransform {
return nullptr;
TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
- return buildDeductionGuide(TemplateParams, FD->isExplicit(), NewTInfo,
- FD->getLocStart(), FD->getLocation(),
- FD->getLocEnd());
+ return buildDeductionGuide(TemplateParams, CD->isExplicit(), NewTInfo,
+ CD->getLocStart(), CD->getLocation(),
+ CD->getLocEnd());
}
/// Build a deduction guide with the specified parameter types.
@@ -1677,17 +1678,15 @@ private:
bool Explicit, TypeSourceInfo *TInfo,
SourceLocation LocStart, SourceLocation Loc,
SourceLocation LocEnd) {
+ DeclarationNameInfo Name(DeductionGuideName, Loc);
ArrayRef<ParmVarDecl *> Params =
TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams();
// Build the implicit deduction guide template.
- auto *Guide = FunctionDecl::Create(SemaRef.Context, DC, LocStart, Loc,
- DeductionGuideName, TInfo->getType(),
- TInfo, SC_None);
+ auto *Guide =
+ CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, Explicit,
+ Name, TInfo->getType(), TInfo, LocEnd);
Guide->setImplicit();
- if (Explicit)
- Guide->setExplicitSpecified();
- Guide->setRangeEnd(LocEnd);
Guide->setParams(Params);
for (auto *Param : Params)
@@ -1749,16 +1748,16 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
D = cast<NamedDecl>(D->getCanonicalDecl());
auto *FTD = dyn_cast<FunctionTemplateDecl>(D);
- auto *FD = FTD ? FTD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D);
+ auto *CD =
+ dyn_cast_or_null<CXXConstructorDecl>(FTD ? FTD->getTemplatedDecl() : D);
// Class-scope explicit specializations (MS extension) do not result in
// deduction guides.
- if (!FD || (!FTD && FD->isFunctionTemplateSpecialization()))
+ if (!CD || (!FTD && CD->isFunctionTemplateSpecialization()))
continue;
- Transform.transformConstructor(FTD, FD);
+ Transform.transformConstructor(FTD, CD);
AddedAny = true;
- CXXConstructorDecl *CD = cast<CXXConstructorDecl>(FD);
AddedCopyOrMove |= CD->isCopyOrMoveConstructor();
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 5d78fd437e..6c3a618fbb 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -968,10 +968,10 @@ bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
/// the template parameter lists of a class template and a constructor template
/// when forming an implicit deduction guide.
static unsigned getFirstInnerIndex(FunctionTemplateDecl *FTD) {
- if (!FTD->isImplicit() || !FTD->getTemplatedDecl()->isDeductionGuide())
+ auto *Guide = dyn_cast<CXXDeductionGuideDecl>(FTD->getTemplatedDecl());
+ if (!Guide || !Guide->isImplicit())
return 0;
- return FTD->getDeclName().getCXXDeductionGuideTemplate()
- ->getTemplateParameters()->size();
+ return Guide->getDeducedTemplate()->getTemplateParameters()->size();
}
/// Determine whether a type denotes a forwarding reference.
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f7db189de8..63c10c0c71 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1599,21 +1599,22 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateArgs);
}
- FunctionDecl *Function =
- FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
- D->getNameInfo(), T, TInfo,
- D->getCanonicalDecl()->getStorageClass(),
- D->isInlineSpecified(), D->hasWrittenPrototype(),
- D->isConstexpr());
- Function->setRangeEnd(D->getSourceRange().getEnd());
+ FunctionDecl *Function;
+ if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D))
+ Function = CXXDeductionGuideDecl::Create(
+ SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
+ D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd());
+ else {
+ Function = FunctionDecl::Create(
+ SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo,
+ D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
+ D->hasWrittenPrototype(), D->isConstexpr());
+ Function->setRangeEnd(D->getSourceRange().getEnd());
+ }
if (D->isInlined())
Function->setImplicitlyInline();
- // A deduction-guide could be explicit.
- if (D->isExplicitSpecified())
- Function->setExplicitSpecified();
-
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
@@ -2781,6 +2782,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
return VisitFunctionDecl(D, nullptr);
}
+Decl *
+TemplateDeclInstantiator::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+ return VisitFunctionDecl(D, nullptr);
+}
+
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
return VisitCXXMethodDecl(D, nullptr);
}
@@ -4958,8 +4964,9 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
}
// An implicit deduction guide acts as if it's within the class template
// specialization described by its name and first N template params.
- if (FD->isDeductionGuide() && FD->isImplicit()) {
- TemplateDecl *TD = FD->getDeclName().getCXXDeductionGuideTemplate();
+ auto *Guide = dyn_cast<CXXDeductionGuideDecl>(FD);
+ if (Guide && Guide->isImplicit()) {
+ TemplateDecl *TD = Guide->getDeducedTemplate();
TemplateArgumentListInfo Args(Loc, Loc);
for (auto Arg : TemplateArgs.getInnermost().take_front(
TD->getTemplateParameters()->size()))
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 65792c7e4d..684ec24303 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -251,6 +251,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::VarTemplateSpecialization:
case Decl::VarTemplatePartialSpecialization:
case Decl::Function:
+ case Decl::CXXDeductionGuide:
case Decl::CXXMethod:
case Decl::CXXConstructor:
case Decl::CXXDestructor:
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 9be3981329..add3b3e828 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -293,6 +293,7 @@ namespace clang {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitDeclaratorDecl(DeclaratorDecl *DD);
void VisitFunctionDecl(FunctionDecl *FD);
+ void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *GD);
void VisitCXXMethodDecl(CXXMethodDecl *D);
void VisitCXXConstructorDecl(CXXConstructorDecl *D);
void VisitCXXDestructorDecl(CXXDestructorDecl *D);
@@ -1786,6 +1787,10 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
return Redecl;
}
+void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+ VisitFunctionDecl(D);
+}
+
void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
VisitFunctionDecl(D);
@@ -3371,6 +3376,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_CXX_RECORD:
D = CXXRecordDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_CXX_DEDUCTION_GUIDE:
+ D = CXXDeductionGuideDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_CXX_METHOD:
D = CXXMethodDecl::CreateDeserialized(Context, ID);
break;
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 3144b87cd4..200be6688b 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -86,6 +86,7 @@ namespace clang {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitDeclaratorDecl(DeclaratorDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
+ void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D);
void VisitCXXMethodDecl(CXXMethodDecl *D);
void VisitCXXConstructorDecl(CXXConstructorDecl *D);
void VisitCXXDestructorDecl(CXXDestructorDecl *D);
@@ -609,6 +610,11 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Code = serialization::DECL_FUNCTION;
}
+void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+ VisitFunctionDecl(D);
+ Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
+}
+
void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
VisitNamedDecl(D);
// FIXME: convert to LazyStmtPtr?
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 673d96374b..216322b9f9 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -5782,6 +5782,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::OMPCapturedExpr:
case Decl::Label: // FIXME: Is this right??
case Decl::ClassScopeFunctionSpecialization:
+ case Decl::CXXDeductionGuide:
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::OMPDeclareReduction: