forked from OSchip/llvm-project
When a template-id refers to a single function template, and the
explicitly-specified template arguments are enough to determine the instantiation, and either template argument deduction fails or is not performed in that context, we can resolve the template-id down to a function template specialization (so sayeth C++0x [temp.arg.explicit]p3). Fixes PR5811. llvm-svn: 91852
This commit is contained in:
parent
bf20018423
commit
8364e6b568
|
@ -589,7 +589,8 @@ def err_temp_copy_deleted : Error<
|
||||||
|
|
||||||
// C++0x decltype
|
// C++0x decltype
|
||||||
def err_cannot_determine_declared_type_of_overloaded_function : Error<
|
def err_cannot_determine_declared_type_of_overloaded_function : Error<
|
||||||
"can't determine the declared type of an overloaded function">;
|
"cannot determine the %select{type|declared type}0 of an overloaded "
|
||||||
|
"function">;
|
||||||
|
|
||||||
// C++0x auto
|
// C++0x auto
|
||||||
def err_auto_variable_cannot_appear_in_own_initializer : Error<
|
def err_auto_variable_cannot_appear_in_own_initializer : Error<
|
||||||
|
@ -1007,6 +1008,8 @@ def err_template_arg_unnamed_type : Error<
|
||||||
"template argument uses unnamed type">;
|
"template argument uses unnamed type">;
|
||||||
def note_template_unnamed_type_here : Note<
|
def note_template_unnamed_type_here : Note<
|
||||||
"unnamed type used in template argument was declared here">;
|
"unnamed type used in template argument was declared here">;
|
||||||
|
def err_template_arg_overload_type : Error<
|
||||||
|
"template argument is the type of an unresolved overloaded function">;
|
||||||
def err_template_arg_not_class_template : Error<
|
def err_template_arg_not_class_template : Error<
|
||||||
"template argument does not refer to a class template or template "
|
"template argument does not refer to a class template or template "
|
||||||
"template parameter">;
|
"template parameter">;
|
||||||
|
|
|
@ -1036,6 +1036,8 @@ public:
|
||||||
|
|
||||||
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
||||||
bool Complain);
|
bool Complain);
|
||||||
|
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
|
||||||
|
|
||||||
Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
|
Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
|
||||||
OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
|
OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
|
||||||
FunctionDecl *Fn);
|
FunctionDecl *Fn);
|
||||||
|
@ -2664,7 +2666,10 @@ public:
|
||||||
TDK_TooFewArguments,
|
TDK_TooFewArguments,
|
||||||
/// \brief The explicitly-specified template arguments were not valid
|
/// \brief The explicitly-specified template arguments were not valid
|
||||||
/// template arguments for the given template.
|
/// template arguments for the given template.
|
||||||
TDK_InvalidExplicitArguments
|
TDK_InvalidExplicitArguments,
|
||||||
|
/// \brief The arguments included an overloaded function name that could
|
||||||
|
/// not be resolved to a suitable function.
|
||||||
|
TDK_FailedOverloadResolution
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Provides information about an attempted template argument
|
/// \brief Provides information about an attempted template argument
|
||||||
|
@ -2778,6 +2783,12 @@ public:
|
||||||
CXXConversionDecl *&Specialization,
|
CXXConversionDecl *&Specialization,
|
||||||
TemplateDeductionInfo &Info);
|
TemplateDeductionInfo &Info);
|
||||||
|
|
||||||
|
TemplateDeductionResult
|
||||||
|
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
||||||
|
const TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||||
|
FunctionDecl *&Specialization,
|
||||||
|
TemplateDeductionInfo &Info);
|
||||||
|
|
||||||
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
||||||
FunctionTemplateDecl *FT2,
|
FunctionTemplateDecl *FT2,
|
||||||
TemplatePartialOrderingContext TPOC);
|
TemplatePartialOrderingContext TPOC);
|
||||||
|
|
|
@ -4591,6 +4591,93 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Given an expression that refers to an overloaded function, try to
|
||||||
|
/// resolve that overloaded function expression down to a single function.
|
||||||
|
///
|
||||||
|
/// This routine can only resolve template-ids that refer to a single function
|
||||||
|
/// template, where that template-id refers to a single template whose template
|
||||||
|
/// arguments are either provided by the template-id or have defaults,
|
||||||
|
/// as described in C++0x [temp.arg.explicit]p3.
|
||||||
|
FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
|
||||||
|
// C++ [over.over]p1:
|
||||||
|
// [...] [Note: any redundant set of parentheses surrounding the
|
||||||
|
// overloaded function name is ignored (5.1). ]
|
||||||
|
Expr *OvlExpr = From->IgnoreParens();
|
||||||
|
|
||||||
|
// C++ [over.over]p1:
|
||||||
|
// [...] The overloaded function name can be preceded by the &
|
||||||
|
// operator.
|
||||||
|
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
|
||||||
|
if (UnOp->getOpcode() == UnaryOperator::AddrOf)
|
||||||
|
OvlExpr = UnOp->getSubExpr()->IgnoreParens();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasExplicitTemplateArgs = false;
|
||||||
|
TemplateArgumentListInfo ExplicitTemplateArgs;
|
||||||
|
|
||||||
|
llvm::SmallVector<NamedDecl*,8> Fns;
|
||||||
|
|
||||||
|
// Look into the overloaded expression.
|
||||||
|
if (UnresolvedLookupExpr *UL
|
||||||
|
= dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
|
||||||
|
Fns.append(UL->decls_begin(), UL->decls_end());
|
||||||
|
if (UL->hasExplicitTemplateArgs()) {
|
||||||
|
HasExplicitTemplateArgs = true;
|
||||||
|
UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
|
||||||
|
}
|
||||||
|
} else if (UnresolvedMemberExpr *ME
|
||||||
|
= dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
|
||||||
|
Fns.append(ME->decls_begin(), ME->decls_end());
|
||||||
|
if (ME->hasExplicitTemplateArgs()) {
|
||||||
|
HasExplicitTemplateArgs = true;
|
||||||
|
ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't actually find any template-ids, we're done.
|
||||||
|
if (Fns.empty() || !HasExplicitTemplateArgs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Look through all of the overloaded functions, searching for one
|
||||||
|
// whose type matches exactly.
|
||||||
|
FunctionDecl *Matched = 0;
|
||||||
|
for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
|
||||||
|
E = Fns.end(); I != E; ++I) {
|
||||||
|
// C++0x [temp.arg.explicit]p3:
|
||||||
|
// [...] In contexts where deduction is done and fails, or in contexts
|
||||||
|
// where deduction is not done, if a template argument list is
|
||||||
|
// specified and it, along with any default template arguments,
|
||||||
|
// identifies a single function template specialization, then the
|
||||||
|
// template-id is an lvalue for the function template specialization.
|
||||||
|
FunctionTemplateDecl *FunctionTemplate = cast<FunctionTemplateDecl>(*I);
|
||||||
|
|
||||||
|
// C++ [over.over]p2:
|
||||||
|
// If the name is a function template, template argument deduction is
|
||||||
|
// done (14.8.2.2), and if the argument deduction succeeds, the
|
||||||
|
// resulting template argument list is used to generate a single
|
||||||
|
// function template specialization, which is added to the set of
|
||||||
|
// overloaded functions considered.
|
||||||
|
// FIXME: We don't really want to build the specialization here, do we?
|
||||||
|
FunctionDecl *Specialization = 0;
|
||||||
|
TemplateDeductionInfo Info(Context);
|
||||||
|
if (TemplateDeductionResult Result
|
||||||
|
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
|
||||||
|
Specialization, Info)) {
|
||||||
|
// FIXME: make a note of the failed deduction for diagnostics.
|
||||||
|
(void)Result;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple matches; we can't resolve to a single declaration.
|
||||||
|
if (Matched)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Matched = Specialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Matched;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Add a single candidate to the overload set.
|
/// \brief Add a single candidate to the overload set.
|
||||||
static void AddOverloadedCallCandidate(Sema &S,
|
static void AddOverloadedCallCandidate(Sema &S,
|
||||||
NamedDecl *Callee,
|
NamedDecl *Callee,
|
||||||
|
|
|
@ -2189,6 +2189,9 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
|
||||||
Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
|
Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
|
||||||
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
|
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
|
||||||
|
SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
|
||||||
|
return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1506,15 +1506,39 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
||||||
ParamType->getAs<PointerType>()->getPointeeType())))
|
ParamType->getAs<PointerType>()->getPointeeType())))
|
||||||
TDF |= TDF_DerivedClass;
|
TDF |= TDF_DerivedClass;
|
||||||
|
|
||||||
|
// FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
|
||||||
|
// pointer parameters.
|
||||||
|
|
||||||
|
if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) {
|
||||||
|
// We know that template argument deduction will fail if the argument is
|
||||||
|
// still an overloaded function. Check whether we can resolve this
|
||||||
|
// argument as a single function template specialization per
|
||||||
|
// C++ [temp.arg.explicit]p3.
|
||||||
|
FunctionDecl *ExplicitSpec
|
||||||
|
= ResolveSingleFunctionTemplateSpecialization(Args[I]);
|
||||||
|
Expr *ResolvedArg = 0;
|
||||||
|
if (ExplicitSpec)
|
||||||
|
ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec);
|
||||||
|
if (!ExplicitSpec || !ResolvedArg) {
|
||||||
|
// Template argument deduction fails if we can't resolve the overloaded
|
||||||
|
// function.
|
||||||
|
return TDK_FailedOverloadResolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the type of the resolved argument.
|
||||||
|
ArgType = ResolvedArg->getType();
|
||||||
|
if (ArgType->isPointerType() || ArgType->isMemberPointerType())
|
||||||
|
TDF |= TDF_IgnoreQualifiers;
|
||||||
|
|
||||||
|
ResolvedArg->Destroy(Context);
|
||||||
|
}
|
||||||
|
|
||||||
if (TemplateDeductionResult Result
|
if (TemplateDeductionResult Result
|
||||||
= ::DeduceTemplateArguments(Context, TemplateParams,
|
= ::DeduceTemplateArguments(Context, TemplateParams,
|
||||||
ParamType, ArgType, Info, Deduced,
|
ParamType, ArgType, Info, Deduced,
|
||||||
TDF))
|
TDF))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
// 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,
|
// FIXME: we need to check that the deduced A is the same as A,
|
||||||
// modulo the various allowed differences.
|
// modulo the various allowed differences.
|
||||||
}
|
}
|
||||||
|
@ -1524,24 +1548,19 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Deduce template arguments when taking the address of a function
|
/// \brief Deduce template arguments when taking the address of a function
|
||||||
/// template (C++ [temp.deduct.funcaddr]) or matching a
|
/// template (C++ [temp.deduct.funcaddr]) or matching a specialization to
|
||||||
|
/// a template.
|
||||||
///
|
///
|
||||||
/// \param FunctionTemplate the function template for which we are performing
|
/// \param FunctionTemplate the function template for which we are performing
|
||||||
/// template argument deduction.
|
/// template argument deduction.
|
||||||
///
|
///
|
||||||
/// \param HasExplicitTemplateArgs whether any template arguments were
|
/// \param ExplicitTemplateArguments the explicitly-specified template
|
||||||
/// explicitly specified.
|
/// arguments.
|
||||||
///
|
|
||||||
/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
|
|
||||||
/// the explicitly-specified template arguments.
|
|
||||||
///
|
|
||||||
/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
|
|
||||||
/// the number of explicitly-specified template arguments in
|
|
||||||
/// @p ExplicitTemplateArguments. This value may be zero.
|
|
||||||
///
|
///
|
||||||
/// \param ArgFunctionType the function type that will be used as the
|
/// \param ArgFunctionType the function type that will be used as the
|
||||||
/// "argument" type (A) when performing template argument deduction from the
|
/// "argument" type (A) when performing template argument deduction from the
|
||||||
/// function template's function type.
|
/// function template's function type. This type may be NULL, if there is no
|
||||||
|
/// argument type to compare against, in C++0x [temp.arg.explicit]p3.
|
||||||
///
|
///
|
||||||
/// \param Specialization if template argument deduction was successful,
|
/// \param Specialization if template argument deduction was successful,
|
||||||
/// this will be set to the function template specialization produced by
|
/// this will be set to the function template specialization produced by
|
||||||
|
@ -1578,14 +1597,16 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
||||||
// Trap any errors that might occur.
|
// Trap any errors that might occur.
|
||||||
SFINAETrap Trap(*this);
|
SFINAETrap Trap(*this);
|
||||||
|
|
||||||
// Deduce template arguments from the function type.
|
if (!ArgFunctionType.isNull()) {
|
||||||
Deduced.resize(TemplateParams->size());
|
// Deduce template arguments from the function type.
|
||||||
if (TemplateDeductionResult Result
|
Deduced.resize(TemplateParams->size());
|
||||||
= ::DeduceTemplateArguments(Context, TemplateParams,
|
if (TemplateDeductionResult Result
|
||||||
FunctionType, ArgFunctionType, Info,
|
= ::DeduceTemplateArguments(Context, TemplateParams,
|
||||||
Deduced, 0))
|
FunctionType, ArgFunctionType, Info,
|
||||||
return Result;
|
Deduced, 0))
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
|
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
|
||||||
Specialization, Info);
|
Specialization, Info);
|
||||||
}
|
}
|
||||||
|
@ -1694,6 +1715,32 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Deduce template arguments for a function template when there is
|
||||||
|
/// nothing to deduce against (C++0x [temp.arg.explicit]p3).
|
||||||
|
///
|
||||||
|
/// \param FunctionTemplate the function template for which we are performing
|
||||||
|
/// template argument deduction.
|
||||||
|
///
|
||||||
|
/// \param ExplicitTemplateArguments the explicitly-specified template
|
||||||
|
/// arguments.
|
||||||
|
///
|
||||||
|
/// \param Specialization if template argument deduction was successful,
|
||||||
|
/// this will be set to the function template specialization produced by
|
||||||
|
/// template argument deduction.
|
||||||
|
///
|
||||||
|
/// \param Info the argument will be updated to provide additional information
|
||||||
|
/// about template argument deduction.
|
||||||
|
///
|
||||||
|
/// \returns the result of template argument deduction.
|
||||||
|
Sema::TemplateDeductionResult
|
||||||
|
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
||||||
|
const TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||||
|
FunctionDecl *&Specialization,
|
||||||
|
TemplateDeductionInfo &Info) {
|
||||||
|
return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
|
||||||
|
QualType(), Specialization, Info);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Stores the result of comparing the qualifiers of two types.
|
/// \brief Stores the result of comparing the qualifiers of two types.
|
||||||
enum DeductionQualifierComparison {
|
enum DeductionQualifierComparison {
|
||||||
NeitherMoreQualified = 0,
|
NeitherMoreQualified = 0,
|
||||||
|
|
|
@ -308,7 +308,11 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
|
||||||
Expr *E = static_cast<Expr *>(DS.getTypeRep());
|
Expr *E = static_cast<Expr *>(DS.getTypeRep());
|
||||||
assert(E && "Didn't get an expression for typeof?");
|
assert(E && "Didn't get an expression for typeof?");
|
||||||
// TypeQuals handled by caller.
|
// TypeQuals handled by caller.
|
||||||
Result = Context.getTypeOfExprType(E);
|
Result = TheSema.BuildTypeofExprType(E);
|
||||||
|
if (Result.isNull()) {
|
||||||
|
Result = Context.IntTy;
|
||||||
|
TheDeclarator.setInvalidType(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DeclSpec::TST_decltype: {
|
case DeclSpec::TST_decltype: {
|
||||||
|
@ -1826,14 +1830,41 @@ QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType Sema::BuildTypeofExprType(Expr *E) {
|
QualType Sema::BuildTypeofExprType(Expr *E) {
|
||||||
|
if (E->getType() == Context.OverloadTy) {
|
||||||
|
// C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a
|
||||||
|
// function template specialization wherever deduction cannot occur.
|
||||||
|
if (FunctionDecl *Specialization
|
||||||
|
= ResolveSingleFunctionTemplateSpecialization(E)) {
|
||||||
|
E = FixOverloadedFunctionReference(E, Specialization);
|
||||||
|
if (!E)
|
||||||
|
return QualType();
|
||||||
|
} else {
|
||||||
|
Diag(E->getLocStart(),
|
||||||
|
diag::err_cannot_determine_declared_type_of_overloaded_function)
|
||||||
|
<< false << E->getSourceRange();
|
||||||
|
return QualType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Context.getTypeOfExprType(E);
|
return Context.getTypeOfExprType(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType Sema::BuildDecltypeType(Expr *E) {
|
QualType Sema::BuildDecltypeType(Expr *E) {
|
||||||
if (E->getType() == Context.OverloadTy) {
|
if (E->getType() == Context.OverloadTy) {
|
||||||
Diag(E->getLocStart(),
|
// C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a
|
||||||
diag::err_cannot_determine_declared_type_of_overloaded_function);
|
// function template specialization wherever deduction cannot occur.
|
||||||
return QualType();
|
if (FunctionDecl *Specialization
|
||||||
|
= ResolveSingleFunctionTemplateSpecialization(E)) {
|
||||||
|
E = FixOverloadedFunctionReference(E, Specialization);
|
||||||
|
if (!E)
|
||||||
|
return QualType();
|
||||||
|
} else {
|
||||||
|
Diag(E->getLocStart(),
|
||||||
|
diag::err_cannot_determine_declared_type_of_overloaded_function)
|
||||||
|
<< true << E->getSourceRange();
|
||||||
|
return QualType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Context.getDecltypeType(E);
|
return Context.getDecltypeType(E);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||||
|
|
||||||
|
// PR5811
|
||||||
|
template <class F> void Call(F f) { f(1); }
|
||||||
|
template <typename T> void f(T);
|
||||||
|
void a() { Call(f<int>); }
|
||||||
|
|
||||||
|
// Check the conversion of a template-id to a pointer
|
||||||
|
template<typename T, T* Address> struct Constant { };
|
||||||
|
Constant<void(int), &f<int> > constant0;
|
||||||
|
|
||||||
|
template<typename T, T* Address> void constant_func();
|
||||||
|
void test_constant_func() {
|
||||||
|
constant_func<void(int), &f<int> >();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check typeof() on a template-id referring to a single function
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct is_same {
|
||||||
|
static const bool value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_same<T, T> {
|
||||||
|
static const bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
int typeof0[is_same<__typeof__(f<int>), void (int)>::value? 1 : -1];
|
||||||
|
int typeof1[is_same<__typeof__(&f<int>), void (*)(int)>::value? 1 : -1];
|
||||||
|
|
||||||
|
template <typename T> void g(T);
|
||||||
|
template <typename T> void g(T, T);
|
||||||
|
|
||||||
|
int typeof2[is_same<__typeof__(g<float>), void (int)>::value? 1 : -1]; // \
|
||||||
|
// expected-error{{cannot determine the type of an overloaded function}} \
|
||||||
|
// FIXME: expected-error{{use of undeclared identifier}}
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
void f();
|
void f();
|
||||||
void f(int);
|
void f(int);
|
||||||
decltype(f) a; // expected-error{{can't determine the declared type of an overloaded function}}
|
decltype(f) a; // expected-error{{cannot determine the declared type of an overloaded function}}
|
||||||
|
|
||||||
template<typename T> struct S {
|
template<typename T> struct S {
|
||||||
decltype(T::f) * f; // expected-error{{can't determine the declared type of an overloaded function}}
|
decltype(T::f) * f; // expected-error{{cannot determine the declared type of an overloaded function}}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct K { void f(); void f(int); };
|
struct K { void f(); void f(int); };
|
||||||
|
|
Loading…
Reference in New Issue