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
This commit is contained in:
Douglas Gregor 2009-08-21 23:19:43 +00:00
Родитель 263b3522ad
Коммит 65ec1fda47
11 изменённых файлов: 461 добавлений и 72 удалений

Просмотреть файл

@ -559,6 +559,11 @@ public:
/// list of conversion functions. /// list of conversion functions.
void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl); 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++ /// isAggregate - Whether this class is an aggregate (C++
/// [dcl.init.aggr]), which is a class with no user-declared /// [dcl.init.aggr]), which is a class with no user-declared
/// constructors, no private or protected non-static data members, /// constructors, no private or protected non-static data members,

Просмотреть файл

@ -279,9 +279,17 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
void CXXRecordDecl::addConversionFunction(ASTContext &Context, void CXXRecordDecl::addConversionFunction(ASTContext &Context,
CXXConversionDecl *ConvDecl) { CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
Conversions.addOverload(ConvDecl); Conversions.addOverload(ConvDecl);
} }
void CXXRecordDecl::addConversionFunction(ASTContext &Context,
FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
Conversions.addOverload(ConvDecl);
}
CXXConstructorDecl * CXXConstructorDecl *
CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {

Просмотреть файл

@ -823,6 +823,9 @@ public:
void AddConversionCandidate(CXXConversionDecl *Conversion, void AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType, Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet); OverloadCandidateSet& CandidateSet);
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet);
void AddSurrogateCandidate(CXXConversionDecl *Conversion, void AddSurrogateCandidate(CXXConversionDecl *Conversion,
const FunctionProtoType *Proto, const FunctionProtoType *Proto,
Expr *Object, Expr **Args, unsigned NumArgs, Expr *Object, Expr **Args, unsigned NumArgs,
@ -2552,6 +2555,16 @@ public:
FunctionDecl *&Specialization, FunctionDecl *&Specialization,
TemplateDeductionInfo &Info); 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, void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
llvm::SmallVectorImpl<bool> &Deduced); llvm::SmallVectorImpl<bool> &Deduced);

Просмотреть файл

@ -1853,9 +1853,6 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
assert(Conversion && "Expected to receive a conversion function declaration"); assert(Conversion && "Expected to receive a conversion function declaration");
// Set the lexical context of this conversion function
Conversion->setLexicalDeclContext(CurContext);
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Conversion->getDeclContext()); CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Conversion->getDeclContext());
// Make sure we aren't redeclaring the conversion function. // Make sure we aren't redeclaring the conversion function.
@ -1887,19 +1884,25 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
} }
if (Conversion->getPreviousDeclaration()) { if (Conversion->getPreviousDeclaration()) {
const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration();
if (FunctionTemplateDecl *ConversionTemplate
= Conversion->getDescribedFunctionTemplate())
ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration();
OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions(); OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
for (OverloadedFunctionDecl::function_iterator for (OverloadedFunctionDecl::function_iterator
Conv = Conversions->function_begin(), Conv = Conversions->function_begin(),
ConvEnd = Conversions->function_end(); ConvEnd = Conversions->function_end();
Conv != ConvEnd; ++Conv) { Conv != ConvEnd; ++Conv) {
if (*Conv if (*Conv == ExpectedPrevDecl) {
== cast_or_null<NamedDecl>(Conversion->getPreviousDeclaration())) {
*Conv = Conversion; *Conv = Conversion;
return DeclPtrTy::make(Conversion); return DeclPtrTy::make(Conversion);
} }
} }
assert(Conversion->isInvalidDecl() && "Conversion should not get here."); 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); ClassDecl->addConversionFunction(Context, Conversion);
return DeclPtrTy::make(Conversion); return DeclPtrTy::make(Conversion);
@ -2845,13 +2848,24 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
for (OverloadedFunctionDecl::function_iterator Func for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin(); = Conversions->function_begin();
Func != Conversions->function_end(); ++Func) { Func != Conversions->function_end(); ++Func) {
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); FunctionTemplateDecl *ConvTemplate
= dyn_cast<FunctionTemplateDecl>(*Func);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
Conv = cast<CXXConversionDecl>(*Func);
// If the conversion function doesn't return a reference type, // If the conversion function doesn't return a reference type,
// it can't be considered for this conversion. // it can't be considered for this conversion.
if (Conv->getConversionType()->isLValueReferenceType() && if (Conv->getConversionType()->isLValueReferenceType() &&
(AllowExplicit || !Conv->isExplicit())) (AllowExplicit || !Conv->isExplicit())) {
AddConversionCandidate(Conv, Init, DeclType, CandidateSet); if (ConvTemplate)
AddTemplateConversionCandidate(ConvTemplate, Init, DeclType,
CandidateSet);
else
AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
}
} }
OverloadCandidateSet::iterator Best; OverloadCandidateSet::iterator Best;

Просмотреть файл

@ -1302,6 +1302,19 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
FromType.getUnqualifiedType() == ToType.getUnqualifiedType(); FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
} }
/// \brief Given a function template or function, extract the function template
/// declaration (if any) and the underlying function declaration.
template<typename T>
static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function,
FunctionTemplateDecl *&FunctionTemplate) {
FunctionTemplate = dyn_cast<FunctionTemplateDecl>(Orig);
if (FunctionTemplate)
Function = cast<T>(FunctionTemplate->getTemplatedDecl());
else
Function = cast<T>(Orig);
}
/// Determines whether there is a user-defined conversion sequence /// Determines whether there is a user-defined conversion sequence
/// (C++ [over.ics.user]) that converts expression From to the type /// (C++ [over.ics.user]) that converts expression From to the type
/// ToType. If such a conversion exists, User will contain the /// 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 for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin(); = Conversions->function_begin();
Func != Conversions->function_end(); ++Func) { Func != Conversions->function_end(); ++Func) {
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); CXXConversionDecl *Conv;
if (AllowExplicit || !Conv->isExplicit()) FunctionTemplateDecl *ConvTemplate;
AddConversionCandidate(Conv, From, ToType, CandidateSet); GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
if (ConvTemplate)
Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
Conv = dyn_cast<CXXConversionDecl>(*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); CandidateSet, SuppressUserConversions, ForceRValue);
} }
/// \brief Add a C++ function template as a candidate in the candidate set, /// \brief Add a C++ function template specialization as a candidate
/// using template argument deduction to produce an appropriate function /// in the candidate set, using template argument deduction to produce
/// template specialization. /// an appropriate function template specialization.
void void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs, bool HasExplicitTemplateArgs,
@ -2345,6 +2370,9 @@ void
Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType, Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet) { OverloadCandidateSet& CandidateSet) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
// Add this candidate // Add this candidate
CandidateSet.push_back(OverloadCandidate()); CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back(); 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<CXXConversionDecl>(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 /// AddSurrogateCandidate - Adds a "surrogate" candidate function that
/// converts the given @c Object to a function pointer via the /// converts the given @c Object to a function pointer via the
/// conversion function @c Conversion, and then attempts to call it /// conversion function @c Conversion, and then attempts to call it
@ -2801,7 +2858,15 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
for (OverloadedFunctionDecl::function_iterator Func for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin(); = Conversions->function_begin();
Func != Conversions->function_end(); ++Func) { Func != Conversions->function_end(); ++Func) {
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*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()) if (AllowExplicitConversions || !Conv->isExplicit())
AddTypesConvertedFrom(Conv->getConversionType(), false, false); AddTypesConvertedFrom(Conv->getConversionType(), false, false);
} }
@ -3543,8 +3608,11 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
// if not that, // if not that,
if (Cand1.Function && Cand1.Function->getPrimaryTemplate() && if (Cand1.Function && Cand1.Function->getPrimaryTemplate() &&
Cand2.Function && Cand2.Function->getPrimaryTemplate()) Cand2.Function && Cand2.Function->getPrimaryTemplate())
// FIXME: Implement partial ordering of function templates. if (FunctionTemplateDecl *BetterTemplate
Diag(SourceLocation(), diag::unsup_function_template_partial_ordering); = getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
Cand2.Function->getPrimaryTemplate(),
true))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
// -- the context is an initialization by user-defined conversion // -- the context is an initialization by user-defined conversion
// (see 8.5, 13.3.1.5) and the standard conversion sequence // (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: // C++ [over.over]p4:
// If more than one function is selected, [...] // If more than one function is selected, [...]
llvm::SmallVector<FunctionDecl *, 4> RemainingMatches; llvm::SmallVector<FunctionDecl *, 4> RemainingMatches;
typedef llvm::SmallPtrSet<FunctionDecl *, 4>::iterator MatchIter;
if (FoundNonTemplateFunction) { if (FoundNonTemplateFunction) {
// [...] any function template specializations in the set are eliminated // [...] any function template specializations in the set are
// if the set also contains a non-template function, [...] // eliminated if the set also contains a non-template function, [...]
for (llvm::SmallPtrSet<FunctionDecl *, 4>::iterator M = Matches.begin(), for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M)
MEnd = Matches.end();
M != MEnd; ++M)
if ((*M)->getPrimaryTemplate() == 0) if ((*M)->getPrimaryTemplate() == 0)
RemainingMatches.push_back(*M); RemainingMatches.push_back(*M);
} else { } else {
// [...] and any given function template specialization F1 is eliminated // [...] and any given function template specialization F1 is
// if the set contains a second function template specialization whose // eliminated if the set contains a second function template
// function template is more specialized than the function template of F1 // specialization whose function template is more specialized
// according to the partial ordering rules of 14.5.5.2. // than the function template of F1 according to the partial
// FIXME: Implement this! // ordering rules of 14.5.5.2.
RemainingMatches.append(Matches.begin(), Matches.end());
// 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 // [...] After such eliminations, if any, there shall remain exactly one
@ -4468,7 +4576,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
Func = Conversions->function_begin(), Func = Conversions->function_begin(),
FuncEnd = Conversions->function_end(); FuncEnd = Conversions->function_end();
Func != FuncEnd; ++Func) { Func != FuncEnd; ++Func) {
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*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 // Strip the reference type (if any) and then the pointer type (if
// any) to get down to what might be a function type. // any) to get down to what might be a function type.

Просмотреть файл

@ -1396,8 +1396,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
// pointer parameters. // 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, return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
Specialization, Info); Specialization, Info);
} }
@ -1472,6 +1475,141 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Specialization, Info); 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<CXXConversionDecl>(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<ReferenceType>())
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<ReferenceType>())
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
// Ps 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 As
// 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<TemplateArgument, 4> 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 qualification
// 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<CXXConversionDecl>(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 static void
MarkDeducedTemplateParameters(Sema &SemaRef, MarkDeducedTemplateParameters(Sema &SemaRef,

Просмотреть файл

@ -505,6 +505,17 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record, Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
Destructor->getLocation(), Name, Destructor->getLocation(), Name,
T, Destructor->isInline(), false); T, Destructor->isInline(), false);
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(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 { } else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
D->getDeclName(), T, D->getDeclaratorInfo(), D->getDeclName(), T, D->getDeclaratorInfo(),
@ -541,11 +552,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
PrevDecl = 0; PrevDecl = 0;
} }
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
if (FunctionTemplate) if (FunctionTemplate)
// Record this function template specialization. // Record this function template specialization.
@ -553,7 +559,13 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
FunctionTemplate, FunctionTemplate,
&TemplateArgs, &TemplateArgs,
InsertPos); 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); Owner->addDecl(Method);
return Method; return Method;
@ -568,37 +580,7 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
} }
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
// FIXME: Look for existing, explicit specializations. return VisitCXXMethodDecl(D);
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> 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<CXXRecordDecl>(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;
} }
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {

Просмотреть файл

@ -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<typename T, unsigned N>
// // 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<typename T, typename A1, typename A2>
// operator T(A1, A2) const () { };
// };
// bullet 3
struct ConvertibleToCVQuals {
template<typename T>
operator T* const() const;
};
void test_cvqual_conv(ConvertibleToCVQuals ctcv) {
int *ip = ctcv;
const int *icp = ctcv;
}

Просмотреть файл

@ -0,0 +1,30 @@
// RUN: clang-cc -fsyntax-only -verify %s
struct AnyPtr {
template<typename T>
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<typename T>
operator T&() const;
};
void test_ref_param(AnyRef ar) {
int &ir = ar;
const float &fr = ar;
int i = ar;
}

Просмотреть файл

@ -0,0 +1,48 @@
// RUN: clang-cc -fsyntax-only %s
struct AnyT {
template<typename T>
operator T();
};
void test_cvqual_ref(AnyT any) {
const int &cir = any;
}
struct AnyThreeLevelPtr {
template<typename T>
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<typename Class, typename T>
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;
}

Просмотреть файл

@ -2111,10 +2111,10 @@ welcome!</p>
</tr> </tr>
<tr> <tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.3 [temp.deduct.conv]</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.3 [temp.deduct.conv]</td>
<td class="broken" align="center"></td> <td class="na" align="center"></td>
<td class="broken" align="center"></td> <td class="advanced" align="center"></td>
<td class="broken" align="center"></td> <td class="medium" align="center"></td>
<td class="broken" align="center"></td> <td class="na" align="center"></td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>