summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaTemplateDeduction.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2013-06-10 20:45:12 +0000
committerdim <dim@FreeBSD.org>2013-06-10 20:45:12 +0000
commitea266cad53e3d49771fa38103913d3ec7a166694 (patch)
tree8f7776b7310bebaf415ac5b69e46e9f928c37144 /lib/Sema/SemaTemplateDeduction.cpp
parentc72c57c9e9b69944e3e009cd5e209634839581d3 (diff)
downloadFreeBSD-src-ea266cad53e3d49771fa38103913d3ec7a166694.zip
FreeBSD-src-ea266cad53e3d49771fa38103913d3ec7a166694.tar.gz
Vendor import of clang tags/RELEASE_33/final r183502 (effectively, 3.3
release): http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_33/final@183502
Diffstat (limited to 'lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp270
1 files changed, 183 insertions, 87 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index f3bbe8a..8efc7a0 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -52,7 +52,11 @@ namespace clang {
TDF_SkipNonDependent = 0x08,
/// \brief Whether we are performing template argument deduction for
/// parameters and arguments in a top-level template argument
- TDF_TopLevelParameterTypeList = 0x10
+ TDF_TopLevelParameterTypeList = 0x10,
+ /// \brief Within template argument deduction from overload resolution per
+ /// C++ [over.over] allow matching function types that are compatible in
+ /// terms of noreturn and default calling convention adjustments.
+ TDF_InOverloadResolution = 0x20
};
}
@@ -867,6 +871,32 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType,
== ParamQs.getCVRQualifiers());
}
+/// \brief Compare types for equality with respect to possibly compatible
+/// function types (noreturn adjustment, implicit calling conventions). If any
+/// of parameter and argument is not a function, just perform type comparison.
+///
+/// \param Param the template parameter type.
+///
+/// \param Arg the argument type.
+bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
+ CanQualType Arg) {
+ const FunctionType *ParamFunction = Param->getAs<FunctionType>(),
+ *ArgFunction = Arg->getAs<FunctionType>();
+
+ // Just compare if not functions.
+ if (!ParamFunction || !ArgFunction)
+ return Param == Arg;
+
+ // Noreturn adjustment.
+ QualType AdjustedParam;
+ if (IsNoReturnConversion(Param, Arg, AdjustedParam))
+ return Arg == Context.getCanonicalType(AdjustedParam);
+
+ // FIXME: Compatible calling conventions.
+
+ return Param == Arg;
+}
+
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
@@ -1103,6 +1133,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_Success;
// Check the cv-qualifiers on the parameter and argument types.
+ CanQualType CanParam = S.Context.getCanonicalType(Param);
+ CanQualType CanArg = S.Context.getCanonicalType(Arg);
if (!(TDF & TDF_IgnoreQualifiers)) {
if (TDF & TDF_ParamWithReferenceType) {
if (hasInconsistentOrSupersetQualifiersOf(Param, Arg))
@@ -1114,14 +1146,25 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// If the parameter type is not dependent, there is nothing to deduce.
if (!Param->isDependentType()) {
- if (!(TDF & TDF_SkipNonDependent) && Param != Arg)
- return Sema::TDK_NonDeducedMismatch;
-
+ if (!(TDF & TDF_SkipNonDependent)) {
+ bool NonDeduced = (TDF & TDF_InOverloadResolution)?
+ !S.isSameOrCompatibleFunctionType(CanParam, CanArg) :
+ Param != Arg;
+ if (NonDeduced) {
+ return Sema::TDK_NonDeducedMismatch;
+ }
+ }
return Sema::TDK_Success;
}
- } else if (!Param->isDependentType() &&
- Param.getUnqualifiedType() == Arg.getUnqualifiedType()) {
- return Sema::TDK_Success;
+ } else if (!Param->isDependentType()) {
+ CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
+ ArgUnqualType = CanArg.getUnqualifiedType();
+ bool Success = (TDF & TDF_InOverloadResolution)?
+ S.isSameOrCompatibleFunctionType(ParamUnqualType,
+ ArgUnqualType) :
+ ParamUnqualType == ArgUnqualType;
+ if (Success)
+ return Sema::TDK_Success;
}
switch (Param->getTypeClass()) {
@@ -2761,21 +2804,25 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
/// Gets the type of a function for template-argument-deducton
/// purposes when it's considered as part of an overload set.
-static QualType GetTypeOfFunction(ASTContext &Context,
- const OverloadExpr::FindResult &R,
+static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
FunctionDecl *Fn) {
+ // We may need to deduce the return type of the function now.
+ if (S.getLangOpts().CPlusPlus1y && Fn->getResultType()->isUndeducedType() &&
+ S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/false))
+ return QualType();
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
if (Method->isInstance()) {
// An instance method that's referenced in a form that doesn't
// look like a member pointer is just invalid.
if (!R.HasFormOfMemberPointer) return QualType();
- return Context.getMemberPointerType(Fn->getType(),
- Context.getTypeDeclType(Method->getParent()).getTypePtr());
+ return S.Context.getMemberPointerType(Fn->getType(),
+ S.Context.getTypeDeclType(Method->getParent()).getTypePtr());
}
if (!R.IsAddressOfOperand) return Fn->getType();
- return Context.getPointerType(Fn->getType());
+ return S.Context.getPointerType(Fn->getType());
}
/// Apply the deduction rules for overload sets.
@@ -2809,7 +2856,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// But we can still look for an explicit specialization.
if (FunctionDecl *ExplicitSpec
= S.ResolveSingleFunctionTemplateSpecialization(Ovl))
- return GetTypeOfFunction(S.Context, R, ExplicitSpec);
+ return GetTypeOfFunction(S, R, ExplicitSpec);
}
return QualType();
@@ -2842,7 +2889,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
}
FunctionDecl *Fn = cast<FunctionDecl>(D);
- QualType ArgType = GetTypeOfFunction(S.Context, R, Fn);
+ QualType ArgType = GetTypeOfFunction(S, R, Fn);
if (ArgType.isNull()) continue;
// Function-to-pointer conversion.
@@ -3316,7 +3363,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info) {
+ TemplateDeductionInfo &Info,
+ bool InOverloadResolution) {
if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid;
@@ -3347,12 +3395,23 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Deduced.resize(TemplateParams->size());
+ // If the function has a deduced return type, substitute it for a dependent
+ // type so that we treat it as a non-deduced context in what follows.
+ bool HasUndeducedReturnType = false;
+ if (getLangOpts().CPlusPlus1y && InOverloadResolution &&
+ Function->getResultType()->isUndeducedType()) {
+ FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
+ HasUndeducedReturnType = true;
+ }
+
if (!ArgFunctionType.isNull()) {
+ unsigned TDF = TDF_TopLevelParameterTypeList;
+ if (InOverloadResolution) TDF |= TDF_InOverloadResolution;
// Deduce template arguments from the function type.
if (TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
- FunctionType, ArgFunctionType, Info,
- Deduced, TDF_TopLevelParameterTypeList))
+ FunctionType, ArgFunctionType,
+ Info, Deduced, TDF))
return Result;
}
@@ -3362,12 +3421,26 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Specialization, Info))
return Result;
- // If the requested function type does not match the actual type of the
- // specialization, template argument deduction fails.
- if (!ArgFunctionType.isNull() &&
- !Context.hasSameType(ArgFunctionType, Specialization->getType()))
+ // If the function has a deduced return type, deduce it now, so we can check
+ // that the deduced function type matches the requested type.
+ if (HasUndeducedReturnType &&
+ Specialization->getResultType()->isUndeducedType() &&
+ DeduceReturnType(Specialization, Info.getLocation(), false))
return TDK_MiscellaneousDeductionFailure;
+ // If the requested function type does not match the actual type of the
+ // specialization with respect to arguments of compatible pointer to function
+ // types, template argument deduction fails.
+ if (!ArgFunctionType.isNull()) {
+ if (InOverloadResolution && !isSameOrCompatibleFunctionType(
+ Context.getCanonicalType(Specialization->getType()),
+ Context.getCanonicalType(ArgFunctionType)))
+ return TDK_MiscellaneousDeductionFailure;
+ else if(!InOverloadResolution &&
+ !Context.hasSameType(Specialization->getType(), ArgFunctionType))
+ return TDK_MiscellaneousDeductionFailure;
+ }
+
return TDK_Success;
}
@@ -3499,9 +3572,11 @@ Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info) {
+ TemplateDeductionInfo &Info,
+ bool InOverloadResolution) {
return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
- QualType(), Specialization, Info);
+ QualType(), Specialization, Info,
+ InOverloadResolution);
}
namespace {
@@ -3522,13 +3597,19 @@ namespace {
// auto &&lref = lvalue;
// must transform into "rvalue reference to T" not "rvalue reference to
// auto type deduced as T" in order for [temp.deduct.call]p3 to apply.
- if (isa<TemplateTypeParmType>(Replacement)) {
+ if (!Replacement.isNull() && isa<TemplateTypeParmType>(Replacement)) {
QualType Result = Replacement;
- TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+ TemplateTypeParmTypeLoc NewTL =
+ TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
} else {
- QualType Result = RebuildAutoType(Replacement);
+ bool Dependent =
+ !Replacement.isNull() && Replacement->isDependentType();
+ QualType Result =
+ SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement,
+ TL.getTypePtr()->isDecltypeAuto(),
+ Dependent);
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
@@ -3539,69 +3620,63 @@ namespace {
// Lambdas never need to be transformed.
return E;
}
- };
- /// Determine whether the specified type (which contains an 'auto' type
- /// specifier) is dependent. This is not trivial, because the 'auto' specifier
- /// itself claims to be type-dependent.
- bool isDependentAutoType(QualType Ty) {
- while (1) {
- QualType Pointee = Ty->getPointeeType();
- if (!Pointee.isNull()) {
- Ty = Pointee;
- } else if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()){
- if (MPT->getClass()->isDependentType())
- return true;
- Ty = MPT->getPointeeType();
- } else if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()){
- for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
- E = FPT->arg_type_end();
- I != E; ++I)
- if ((*I)->isDependentType())
- return true;
- Ty = FPT->getResultType();
- } else if (Ty->isDependentSizedArrayType()) {
- return true;
- } else if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) {
- Ty = AT->getElementType();
- } else if (Ty->getAs<DependentSizedExtVectorType>()) {
- return true;
- } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
- Ty = VT->getElementType();
- } else {
- break;
- }
+ QualType Apply(TypeLoc TL) {
+ // Create some scratch storage for the transformed type locations.
+ // FIXME: We're just going to throw this information away. Don't build it.
+ TypeLocBuilder TLB;
+ TLB.reserve(TL.getFullDataSize());
+ return TransformType(TLB, TL);
}
- assert(Ty->getAs<AutoType>() && "didn't find 'auto' in auto type");
- return false;
- }
+ };
+}
+
+Sema::DeduceAutoResult
+Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) {
+ return DeduceAutoType(Type->getTypeLoc(), Init, Result);
}
-/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6)
+/// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
///
/// \param Type the type pattern using the auto type-specifier.
-///
/// \param Init the initializer for the variable whose type is to be deduced.
-///
/// \param Result if type deduction was successful, this will be set to the
-/// deduced type. This may still contain undeduced autos if the type is
-/// dependent. This will be set to null if deduction succeeded, but auto
-/// substitution failed; the appropriate diagnostic will already have been
-/// produced in that case.
+/// deduced type.
Sema::DeduceAutoResult
-Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
- TypeSourceInfo *&Result) {
+Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
if (Init->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(Init);
- if (result.isInvalid()) return DAR_FailedAlreadyDiagnosed;
- Init = result.take();
+ ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
+ if (NonPlaceholder.isInvalid())
+ return DAR_FailedAlreadyDiagnosed;
+ Init = NonPlaceholder.take();
}
- if (Init->isTypeDependent() || isDependentAutoType(Type->getType())) {
- Result = Type;
+ if (Init->isTypeDependent() || Type.getType()->isDependentType()) {
+ Result = SubstituteAutoTransform(*this, Context.DependentTy).Apply(Type);
+ assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
+ // If this is a 'decltype(auto)' specifier, do the decltype dance.
+ // Since 'decltype(auto)' can only occur at the top of the type, we
+ // don't need to go digging for it.
+ if (const AutoType *AT = Type.getType()->getAs<AutoType>()) {
+ if (AT->isDecltypeAuto()) {
+ if (isa<InitListExpr>(Init)) {
+ Diag(Init->getLocStart(), diag::err_decltype_auto_initializer_list);
+ return DAR_FailedAlreadyDiagnosed;
+ }
+
+ QualType Deduced = BuildDecltypeType(Init, Init->getLocStart());
+ // FIXME: Support a non-canonical deduced type for 'auto'.
+ Deduced = Context.getCanonicalType(Deduced);
+ Result = SubstituteAutoTransform(*this, Deduced).Apply(Type);
+ if (Result.isNull())
+ return DAR_FailedAlreadyDiagnosed;
+ return DAR_Succeeded;
+ }
+ }
+
SourceLocation Loc = Init->getExprLoc();
LocalInstantiationScope InstScope(*this);
@@ -3615,10 +3690,9 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr,
Loc);
- TypeSourceInfo *FuncParamInfo =
- SubstituteAutoTransform(*this, TemplArg).TransformType(Type);
- assert(FuncParamInfo && "substituting template parameter for 'auto' failed");
- QualType FuncParam = FuncParamInfo->getType();
+ QualType FuncParam = SubstituteAutoTransform(*this, TemplArg).Apply(Type);
+ assert(!FuncParam.isNull() &&
+ "substituting template parameter for 'auto' failed");
// Deduce type of TemplParam in Func(Init)
SmallVector<DeducedTemplateArgument, 1> Deduced;
@@ -3659,21 +3733,27 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
return DAR_FailedAlreadyDiagnosed;
}
- Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
+ Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type);
+ if (Result.isNull())
+ return DAR_FailedAlreadyDiagnosed;
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
- if (!InitList && Result &&
- CheckOriginalCallArgDeduction(*this,
+ if (!InitList && !Result.isNull() &&
+ CheckOriginalCallArgDeduction(*this,
Sema::OriginalCallArg(FuncParam,0,InitType),
- Result->getType())) {
- Result = 0;
+ Result)) {
+ Result = QualType();
return DAR_Failed;
}
return DAR_Succeeded;
}
+QualType Sema::SubstAutoType(QualType Type, QualType Deduced) {
+ return SubstituteAutoTransform(*this, Deduced).TransformType(Type);
+}
+
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
if (isa<InitListExpr>(Init))
Diag(VDecl->getLocation(),
@@ -3685,6 +3765,22 @@ void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
<< Init->getSourceRange();
}
+bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
+ bool Diagnose) {
+ assert(FD->getResultType()->isUndeducedType());
+
+ if (FD->getTemplateInstantiationPattern())
+ InstantiateFunctionDefinition(Loc, FD);
+
+ bool StillUndeduced = FD->getResultType()->isUndeducedType();
+ if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) {
+ Diag(Loc, diag::err_auto_fn_used_before_defined) << FD;
+ Diag(FD->getLocation(), diag::note_callee_decl) << FD;
+ }
+
+ return StillUndeduced;
+}
+
static void
MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
@@ -4053,7 +4149,7 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
/// template argument deduction.
UnresolvedSetIterator
Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
- UnresolvedSetIterator SpecEnd,
+ UnresolvedSetIterator SpecEnd,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments,
SourceLocation Loc,
@@ -4110,11 +4206,10 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
}
// Diagnose the ambiguity.
- if (Complain)
+ if (Complain) {
Diag(Loc, AmbigDiag);
- if (Complain)
- // FIXME: Can we order the candidates in some sane way?
+ // FIXME: Can we order the candidates in some sane way?
for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) {
PartialDiagnostic PD = CandidateDiag;
PD << getTemplateArgumentBindingsText(
@@ -4125,6 +4220,7 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
TargetType);
Diag((*I)->getLocation(), PD);
}
+ }
return SpecEnd;
}
OpenPOWER on IntegriCloud