From 65ec1fda479688d143fe2403242cd9c730c800a1 Mon Sep 17 00:00:00 2001
From: Douglas Gregor
Date: Fri, 21 Aug 2009 23:19:43 +0000
Subject: [PATCH] Implement conversion function templates, along with the
ability to use template argument deduction from a conversion function (C++
[temp.deduct.conv]) with implicit conversions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79693 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/AST/DeclCXX.h | 5 +
lib/AST/DeclCXX.cpp | 8 +
lib/Sema/Sema.h | 13 ++
lib/Sema/SemaDeclCXX.cpp | 32 +++-
lib/Sema/SemaOverload.cpp | 157 +++++++++++++++---
lib/Sema/SemaTemplateDeduction.cpp | 140 +++++++++++++++-
lib/Sema/SemaTemplateInstantiateDecl.cpp | 56 +++----
.../temp.deduct/temp.deduct.conv/p2.cpp | 36 ++++
.../temp.deduct/temp.deduct.conv/p3.cpp | 30 ++++
.../temp.deduct/temp.deduct.conv/p4.cpp | 48 ++++++
www/cxx_status.html | 8 +-
11 files changed, 461 insertions(+), 72 deletions(-)
create mode 100644 test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
create mode 100644 test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
create mode 100644 test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index bffedfcd78..60db8c8334 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -559,6 +559,11 @@ public:
/// list of conversion functions.
void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl);
+ /// \brief Add a new conversion function template to the list of conversion
+ /// functions.
+ void addConversionFunction(ASTContext &Context,
+ FunctionTemplateDecl *ConvDecl);
+
/// isAggregate - Whether this class is an aggregate (C++
/// [dcl.init.aggr]), which is a class with no user-declared
/// constructors, no private or protected non-static data members,
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 5c0bbec1ff..40870bed8d 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -279,9 +279,17 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
void CXXRecordDecl::addConversionFunction(ASTContext &Context,
CXXConversionDecl *ConvDecl) {
+ assert(!ConvDecl->getDescribedFunctionTemplate() &&
+ "Conversion function templates should cast to FunctionTemplateDecl.");
Conversions.addOverload(ConvDecl);
}
+void CXXRecordDecl::addConversionFunction(ASTContext &Context,
+ FunctionTemplateDecl *ConvDecl) {
+ assert(isa(ConvDecl->getTemplatedDecl()) &&
+ "Function template is not a conversion function template");
+ Conversions.addOverload(ConvDecl);
+}
CXXConstructorDecl *
CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 9b9d6ebf03..3e0eae57ce 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -823,6 +823,9 @@ public:
void AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
+ void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr *From, QualType ToType,
+ OverloadCandidateSet &CandidateSet);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
const FunctionProtoType *Proto,
Expr *Object, Expr **Args, unsigned NumArgs,
@@ -2552,6 +2555,16 @@ public:
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);
+ TemplateDeductionResult
+ DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ QualType ToType,
+ CXXConversionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
+ FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ bool isCallContext);
+
void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
llvm::SmallVectorImpl &Deduced);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 49ad45ad7a..79dc24e596 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1853,9 +1853,6 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
assert(Conversion && "Expected to receive a conversion function declaration");
- // Set the lexical context of this conversion function
- Conversion->setLexicalDeclContext(CurContext);
-
CXXRecordDecl *ClassDecl = cast(Conversion->getDeclContext());
// Make sure we aren't redeclaring the conversion function.
@@ -1887,19 +1884,25 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
}
if (Conversion->getPreviousDeclaration()) {
+ const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration();
+ if (FunctionTemplateDecl *ConversionTemplate
+ = Conversion->getDescribedFunctionTemplate())
+ ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration();
OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
for (OverloadedFunctionDecl::function_iterator
Conv = Conversions->function_begin(),
ConvEnd = Conversions->function_end();
Conv != ConvEnd; ++Conv) {
- if (*Conv
- == cast_or_null(Conversion->getPreviousDeclaration())) {
+ if (*Conv == ExpectedPrevDecl) {
*Conv = Conversion;
return DeclPtrTy::make(Conversion);
}
}
assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
- } else
+ } else if (FunctionTemplateDecl *ConversionTemplate
+ = Conversion->getDescribedFunctionTemplate())
+ ClassDecl->addConversionFunction(Context, ConversionTemplate);
+ else if (!Conversion->getPrimaryTemplate()) // ignore specializations
ClassDecl->addConversionFunction(Context, Conversion);
return DeclPtrTy::make(Conversion);
@@ -2845,13 +2848,24 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv = cast(*Func);
+ FunctionTemplateDecl *ConvTemplate
+ = dyn_cast(*Func);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast(*Func);
// If the conversion function doesn't return a reference type,
// it can't be considered for this conversion.
if (Conv->getConversionType()->isLValueReferenceType() &&
- (AllowExplicit || !Conv->isExplicit()))
- AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+ (AllowExplicit || !Conv->isExplicit())) {
+ if (ConvTemplate)
+ AddTemplateConversionCandidate(ConvTemplate, Init, DeclType,
+ CandidateSet);
+ else
+ AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+ }
}
OverloadCandidateSet::iterator Best;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index f21b38a649..ada1a2b432 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1302,6 +1302,19 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
}
+/// \brief Given a function template or function, extract the function template
+/// declaration (if any) and the underlying function declaration.
+template
+static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function,
+ FunctionTemplateDecl *&FunctionTemplate) {
+ FunctionTemplate = dyn_cast(Orig);
+ if (FunctionTemplate)
+ Function = cast(FunctionTemplate->getTemplatedDecl());
+ else
+ Function = cast(Orig);
+}
+
+
/// Determines whether there is a user-defined conversion sequence
/// (C++ [over.ics.user]) that converts expression From to the type
/// ToType. If such a conversion exists, User will contain the
@@ -1381,9 +1394,21 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv = cast(*Func);
- if (AllowExplicit || !Conv->isExplicit())
- AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+ if (ConvTemplate)
+ Conv = dyn_cast(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = dyn_cast(*Func);
+
+ if (AllowExplicit || !Conv->isExplicit()) {
+ if (ConvTemplate)
+ AddTemplateConversionCandidate(ConvTemplate, From, ToType,
+ CandidateSet);
+ else
+ AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ }
}
}
}
@@ -2295,9 +2320,9 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
CandidateSet, SuppressUserConversions, ForceRValue);
}
-/// \brief Add a C++ function template as a candidate in the candidate set,
-/// using template argument deduction to produce an appropriate function
-/// template specialization.
+/// \brief Add a C++ function template specialization as a candidate
+/// in the candidate set, using template argument deduction to produce
+/// an appropriate function template specialization.
void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
@@ -2345,6 +2370,9 @@ void
Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet) {
+ assert(!Conversion->getDescribedFunctionTemplate() &&
+ "Conversion function templates use AddTemplateConversionCandidate");
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2404,6 +2432,35 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
}
}
+/// \brief Adds a conversion function template specialization
+/// candidate to the overload set, using template argument deduction
+/// to deduce the template arguments of the conversion function
+/// template from the type that we are converting to (C++
+/// [temp.deduct.conv]).
+void
+Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr *From, QualType ToType,
+ OverloadCandidateSet &CandidateSet) {
+ assert(isa(FunctionTemplate->getTemplatedDecl()) &&
+ "Only conversion function templates permitted here");
+
+ TemplateDeductionInfo Info(Context);
+ CXXConversionDecl *Specialization = 0;
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(FunctionTemplate, ToType,
+ Specialization, Info)) {
+ // FIXME: Record what happened with template argument deduction, so
+ // that we can give the user a beautiful diagnostic.
+ (void)Result;
+ return;
+ }
+
+ // Add the conversion function template specialization produced by
+ // template argument deduction as a candidate.
+ assert(Specialization && "Missing function template specialization?");
+ AddConversionCandidate(Specialization, From, ToType, CandidateSet);
+}
+
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
/// converts the given @c Object to a function pointer via the
/// conversion function @c Conversion, and then attempts to call it
@@ -2801,7 +2858,15 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv = cast(*Func);
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+
+ // Skip conversion function templates; they don't tell us anything
+ // about which builtin types we can convert to.
+ if (ConvTemplate)
+ continue;
+
if (AllowExplicitConversions || !Conv->isExplicit())
AddTypesConvertedFrom(Conv->getConversionType(), false, false);
}
@@ -3543,8 +3608,11 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
// if not that,
if (Cand1.Function && Cand1.Function->getPrimaryTemplate() &&
Cand2.Function && Cand2.Function->getPrimaryTemplate())
- // FIXME: Implement partial ordering of function templates.
- Diag(SourceLocation(), diag::unsup_function_template_partial_ordering);
+ if (FunctionTemplateDecl *BetterTemplate
+ = getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
+ Cand2.Function->getPrimaryTemplate(),
+ true))
+ return BetterTemplate == Cand1.Function->getPrimaryTemplate();
// -- the context is an initialization by user-defined conversion
// (see 8.5, 13.3.1.5) and the standard conversion sequence
@@ -3842,21 +3910,61 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// C++ [over.over]p4:
// If more than one function is selected, [...]
llvm::SmallVector RemainingMatches;
+ typedef llvm::SmallPtrSet::iterator MatchIter;
if (FoundNonTemplateFunction) {
- // [...] any function template specializations in the set are eliminated
- // if the set also contains a non-template function, [...]
- for (llvm::SmallPtrSet::iterator M = Matches.begin(),
- MEnd = Matches.end();
- M != MEnd; ++M)
+ // [...] any function template specializations in the set are
+ // eliminated if the set also contains a non-template function, [...]
+ for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M)
if ((*M)->getPrimaryTemplate() == 0)
RemainingMatches.push_back(*M);
} else {
- // [...] and any given function template specialization F1 is eliminated
- // if the set contains a second function template specialization whose
- // function template is more specialized than the function template of F1
- // according to the partial ordering rules of 14.5.5.2.
- // FIXME: Implement this!
- RemainingMatches.append(Matches.begin(), Matches.end());
+ // [...] and any given function template specialization F1 is
+ // eliminated if the set contains a second function template
+ // specialization whose function template is more specialized
+ // than the function template of F1 according to the partial
+ // ordering rules of 14.5.5.2.
+
+ // The algorithm specified above is quadratic. We instead use a
+ // two-pass algorithm (similar to the one used to identify the
+ // best viable function in an overload set) that identifies the
+ // best function template (if it exists).
+ MatchIter Best = Matches.begin();
+ MatchIter M = Best, MEnd = Matches.end();
+ // Find the most specialized function.
+ for (++M; M != MEnd; ++M)
+ if (getMoreSpecializedTemplate((*M)->getPrimaryTemplate(),
+ (*Best)->getPrimaryTemplate(),
+ false)
+ == (*M)->getPrimaryTemplate())
+ Best = M;
+
+ // Determine whether this function template is more specialized
+ // that all of the others.
+ bool Ambiguous = false;
+ for (M = Matches.begin(); M != MEnd; ++M) {
+ if (M != Best &&
+ getMoreSpecializedTemplate((*M)->getPrimaryTemplate(),
+ (*Best)->getPrimaryTemplate(),
+ false)
+ != (*Best)->getPrimaryTemplate()) {
+ Ambiguous = true;
+ break;
+ }
+ }
+
+ // If one function template was more specialized than all of the
+ // others, return it.
+ if (!Ambiguous)
+ return *Best;
+
+ // We could not find a most-specialized function template, which
+ // is equivalent to having a set of function templates with more
+ // than one such template. So, we place all of the function
+ // templates into the set of remaining matches and produce a
+ // diagnostic below. FIXME: we could perform the quadratic
+ // algorithm here, pruning the result set to limit the number of
+ // candidates output later.
+ RemainingMatches.append(Matches.begin(), Matches.end());
}
// [...] After such eliminations, if any, there shall remain exactly one
@@ -4468,7 +4576,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
Func = Conversions->function_begin(),
FuncEnd = Conversions->function_end();
Func != FuncEnd; ++Func) {
- CXXConversionDecl *Conv = cast(*Func);
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+
+ // Skip over templated conversion functions; they aren't
+ // surrogates.
+ if (ConvTemplate)
+ continue;
// Strip the reference type (if any) and then the pointer type (if
// any) to get down to what might be a function type.
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index b3d370ab12..3a1722671f 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1396,8 +1396,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
// pointer parameters.
+
+ // FIXME: we need to check that the deduced A is the same as A,
+ // modulo the various allowed differences.
}
-
+
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
Specialization, Info);
}
@@ -1472,6 +1475,141 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Specialization, Info);
}
+/// \brief Deduce template arguments for a templated conversion
+/// function (C++ [temp.deduct.conv]) and, if successful, produce a
+/// conversion function template specialization.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ QualType ToType,
+ CXXConversionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ CXXConversionDecl *Conv
+ = cast(FunctionTemplate->getTemplatedDecl());
+ QualType FromType = Conv->getConversionType();
+
+ // Canonicalize the types for deduction.
+ QualType P = Context.getCanonicalType(FromType);
+ QualType A = Context.getCanonicalType(ToType);
+
+ // C++0x [temp.deduct.conv]p3:
+ // If P is a reference type, the type referred to by P is used for
+ // type deduction.
+ if (const ReferenceType *PRef = P->getAs())
+ P = PRef->getPointeeType();
+
+ // C++0x [temp.deduct.conv]p3:
+ // If A is a reference type, the type referred to by A is used
+ // for type deduction.
+ if (const ReferenceType *ARef = A->getAs())
+ A = ARef->getPointeeType();
+ // C++ [temp.deduct.conv]p2:
+ //
+ // If A is not a reference type:
+ else {
+ assert(!A->isReferenceType() && "Reference types were handled above");
+
+ // - If P is an array type, the pointer type produced by the
+ // array-to-pointer standard conversion (4.2) is used in place
+ // of P for type deduction; otherwise,
+ if (P->isArrayType())
+ P = Context.getArrayDecayedType(P);
+ // - If P is a function type, the pointer type produced by the
+ // function-to-pointer standard conversion (4.3) is used in
+ // place of P for type deduction; otherwise,
+ else if (P->isFunctionType())
+ P = Context.getPointerType(P);
+ // - If P is a cv-qualified type, the top level cv-qualifiers of
+ // Pâs type are ignored for type deduction.
+ else
+ P = P.getUnqualifiedType();
+
+ // C++0x [temp.deduct.conv]p3:
+ // If A is a cv-qualified type, the top level cv-qualifiers of Aâs
+ // type are ignored for type deduction.
+ A = A.getUnqualifiedType();
+ }
+
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // C++ [temp.deduct.conv]p1:
+ // Template argument deduction is done by comparing the return
+ // type of the template conversion function (call it P) with the
+ // type that is required as the result of the conversion (call it
+ // A) as described in 14.8.2.4.
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ llvm::SmallVector Deduced;
+ Deduced.resize(TemplateParams->size());
+
+ // C++0x [temp.deduct.conv]p4:
+ // In general, the deduction process attempts to find template
+ // argument values that will make the deduced A identical to
+ // A. However, there are two cases that allow a difference:
+ unsigned TDF = 0;
+ // - If the original A is a reference type, A can be more
+ // cv-qualified than the deduced A (i.e., the type referred to
+ // by the reference)
+ if (ToType->isReferenceType())
+ TDF |= TDF_ParamWithReferenceType;
+ // - The deduced A can be another pointer or pointer to member
+ // type that can be converted to A via a qualiï¬cation
+ // conversion.
+ //
+ // (C++0x [temp.deduct.conv]p6 clarifies that this only happens when
+ // both P and A are pointers or member pointers. In this case, we
+ // just ignore cv-qualifiers completely).
+ if ((P->isPointerType() && A->isPointerType()) ||
+ (P->isMemberPointerType() && P->isMemberPointerType()))
+ TDF |= TDF_IgnoreQualifiers;
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context, TemplateParams,
+ P, A, Info, Deduced, TDF))
+ return Result;
+
+ // FIXME: we need to check that the deduced A is the same as A,
+ // modulo the various allowed differences.
+
+ // Finish template argument deduction.
+ FunctionDecl *Spec = 0;
+ TemplateDeductionResult Result
+ = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info);
+ Specialization = cast_or_null(Spec);
+ return Result;
+}
+
+/// \brief Returns the more specialization function template according
+/// to the rules of function template partial ordering (C++ [temp.func.order]).
+///
+/// \param FT1 the first function template
+///
+/// \param FT2 the second function template
+///
+/// \param isCallContext whether partial ordering is being performed
+/// for a function call (which ignores the return types of the
+/// functions).
+///
+/// \returns the more specialization function template. If neither
+/// template is more specialized, returns NULL.
+FunctionTemplateDecl *
+Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ bool isCallContext) {
+#if 0
+ // FIXME: Implement this
+ bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, isCallContext);
+ bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, isCallContext);
+ if (Better1 == Better2)
+ return 0;
+ if (Better1)
+ return FT1;
+ return FT2;
+#else
+ Diag(SourceLocation(), diag::unsup_function_template_partial_ordering);
+ return 0;
+#endif
+}
static void
MarkDeducedTemplateParameters(Sema &SemaRef,
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ff97631e72..ded49b33ab 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -505,6 +505,17 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
Destructor->getLocation(), Name,
T, Destructor->isInline(), false);
+ } else if (CXXConversionDecl *Conversion = dyn_cast(D)) {
+ CanQualType ConvTy
+ = SemaRef.Context.getCanonicalType(
+ T->getAsFunctionType()->getResultType());
+ Name = SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(
+ ConvTy);
+ Method = CXXConversionDecl::Create(SemaRef.Context, Record,
+ Conversion->getLocation(), Name,
+ T, Conversion->getDeclaratorInfo(),
+ Conversion->isInline(),
+ Conversion->isExplicit());
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
D->getDeclName(), T, D->getDeclaratorInfo(),
@@ -541,11 +552,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
PrevDecl = 0;
}
-
- bool Redeclaration = false;
- bool OverloadableAttrRequired = false;
- SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
- /*FIXME:*/OverloadableAttrRequired);
if (FunctionTemplate)
// Record this function template specialization.
@@ -553,7 +559,13 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
FunctionTemplate,
&TemplateArgs,
InsertPos);
- else if (!Method->isInvalidDecl() || !PrevDecl)
+
+ bool Redeclaration = false;
+ bool OverloadableAttrRequired = false;
+ SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired);
+
+ if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl))
Owner->addDecl(Method);
return Method;
@@ -568,37 +580,7 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- Sema::LocalInstantiationScope Scope(SemaRef);
-
- llvm::SmallVector Params;
- QualType T = InstantiateFunctionType(D, Params);
- if (T.isNull())
- return 0;
- assert(Params.size() == 0 && "Destructor with parameters?");
-
- // Build the instantiated conversion declaration.
- CXXRecordDecl *Record = cast(Owner);
- QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
- CanQualType ConvTy
- = SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType());
- CXXConversionDecl *Conversion
- = CXXConversionDecl::Create(SemaRef.Context, Record,
- D->getLocation(),
- SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy),
- T, D->getDeclaratorInfo(),
- D->isInline(), D->isExplicit());
- Conversion->setInstantiationOfMemberFunction(D);
- if (InitMethodInstantiation(Conversion, D))
- Conversion->setInvalidDecl();
-
- bool Redeclaration = false;
- bool OverloadableAttrRequired = false;
- NamedDecl *PrevDecl = 0;
- SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration,
- /*FIXME:*/OverloadableAttrRequired);
- Owner->addDecl(Conversion);
- return Conversion;
+ return VisitCXXMethodDecl(D);
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
new file mode 100644
index 0000000000..7d175781c2
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// FIXME: [temp.deduct.conv]p2 bullets 1 and 2 can't actually happen without
+// references?
+// struct ConvertibleToArray {
+// // template
+// // operator T(()[]) const;
+
+// private:
+// typedef int array[17];
+
+// operator array() const;
+// };
+
+// void test_array(ConvertibleToArray cta) {
+// int *ip = cta;
+// ip = cta;
+// const float *cfp = cta;
+// }
+
+// bullet 2
+// struct ConvertibleToFunction {
+// template
+// operator T(A1, A2) const () { };
+// };
+
+// bullet 3
+struct ConvertibleToCVQuals {
+ template
+ operator T* const() const;
+};
+
+void test_cvqual_conv(ConvertibleToCVQuals ctcv) {
+ int *ip = ctcv;
+ const int *icp = ctcv;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
new file mode 100644
index 0000000000..95bd7fe121
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct AnyPtr {
+ template
+ operator T*() const;
+};
+
+// If A is a cv-qualified type, the top level cv-qualifiers of A's type
+// are ignored for type deduction.
+void test_cvquals(AnyPtr ap) {
+ int* const ip = ap;
+ const float * const volatile fp = ap;
+}
+
+// If A is a reference type, the type referred to by A is used for
+// type deduction.
+void test_ref_arg(AnyPtr ap) {
+ const int* const &ip = ap;
+ double * const &dp = ap;
+}
+
+struct AnyRef {
+ template
+ operator T&() const;
+};
+
+void test_ref_param(AnyRef ar) {
+ int &ir = ar;
+ const float &fr = ar;
+ int i = ar;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp
new file mode 100644
index 0000000000..439afa8c04
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp
@@ -0,0 +1,48 @@
+// RUN: clang-cc -fsyntax-only %s
+
+struct AnyT {
+ template
+ operator T();
+};
+
+void test_cvqual_ref(AnyT any) {
+ const int &cir = any;
+}
+
+struct AnyThreeLevelPtr {
+ template
+ operator T***() const;
+ // FIXME: Can't handle definitions of member templates yet
+#if 0
+ {
+ T x = 0;
+ x = 0; // will fail if T is deduced to a const type
+ // (EDG and GCC get this wrong)
+ return 0;
+ }
+#endif
+};
+
+void test_deduce_with_qual(AnyThreeLevelPtr a3) {
+ int * const * const * const ip = a3;
+}
+
+struct X { };
+
+struct AnyPtrMem {
+ template
+ operator T Class::*() const;
+ // FIXME: Can't handle definitions of member templates yet
+#if 0
+ {
+ T x = 0;
+ x = 0; // will fail if T is deduced to a const type.
+ // (EDG and GCC get this wrong)
+ return 0;
+ }
+#endif
+};
+
+void test_deduce_ptrmem_with_qual(AnyPtrMem apm) {
+ const float X::* pm = apm;
+}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 5985e6c5e7..be86c5f3ee 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -2111,10 +2111,10 @@ welcome!
14.8.2.3 [temp.deduct.conv] |
- |
- |
- |
- |
+ |
+ |
+ |
+ |
|
--
2.40.0