зеркало из https://github.com/microsoft/clang.git
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:
Родитель
263b3522ad
Коммит
65ec1fda47
|
@ -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,
|
||||
|
|
|
@ -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<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
|
||||
"Function template is not a conversion function template");
|
||||
Conversions.addOverload(ConvDecl);
|
||||
}
|
||||
|
||||
CXXConstructorDecl *
|
||||
CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
|
||||
|
|
|
@ -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<bool> &Deduced);
|
||||
|
||||
|
|
|
@ -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<CXXRecordDecl>(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<NamedDecl>(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<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,
|
||||
// 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;
|
||||
|
|
|
@ -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<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
|
||||
/// (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<CXXConversionDecl>(*Func);
|
||||
if (AllowExplicit || !Conv->isExplicit())
|
||||
AddConversionCandidate(Conv, From, ToType, CandidateSet);
|
||||
CXXConversionDecl *Conv;
|
||||
FunctionTemplateDecl *ConvTemplate;
|
||||
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);
|
||||
}
|
||||
|
||||
/// \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<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
|
||||
/// 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<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())
|
||||
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<FunctionDecl *, 4> RemainingMatches;
|
||||
typedef llvm::SmallPtrSet<FunctionDecl *, 4>::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<FunctionDecl *, 4>::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<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
|
||||
// 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
|
||||
// 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<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
|
||||
// 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<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
|
||||
MarkDeducedTemplateParameters(Sema &SemaRef,
|
||||
|
|
|
@ -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<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 {
|
||||
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<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;
|
||||
return VisitCXXMethodDecl(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>
|
||||
<td> 14.8.2.3 [temp.deduct.conv]</td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="na" align="center"></td>
|
||||
<td class="advanced" align="center"></td>
|
||||
<td class="medium" align="center"></td>
|
||||
<td class="na" align="center"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
Загрузка…
Ссылка в новой задаче