зеркало из https://github.com/microsoft/clang.git
Handle the resolution of a reference to a function template (which
includes explicitly-specified template arguments) to a function template specialization in cases where no deduction is performed or deduction fails. Patch by Faisal Vali, fixes PR7505! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126048 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
6c94837815
Коммит
1be8eec3dd
include/clang
lib/Sema
test
|
@ -2686,6 +2686,10 @@ def err_bad_reinterpret_cast_overload : Error<
|
|||
def err_bad_static_cast_overload : Error<
|
||||
"address of overloaded function %0 cannot be static_cast to type %1">;
|
||||
|
||||
def err_bad_cstyle_cast_overload : Error<
|
||||
"address of overloaded function %0 cannot be cast to type %1">;
|
||||
|
||||
|
||||
def err_bad_cxx_cast_generic : Error<
|
||||
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
|
||||
"functional-style cast}0 from %1 to %2 is not allowed">;
|
||||
|
|
|
@ -1247,12 +1247,28 @@ public:
|
|||
OverloadCandidateSet& CandidateSet,
|
||||
bool PartialOverloading = false);
|
||||
|
||||
// Emit as a 'note' the specific overload candidate
|
||||
void NoteOverloadCandidate(FunctionDecl *Fn);
|
||||
|
||||
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
||||
// Emit as a series of 'note's all template and non-templates
|
||||
// identified by the expression Expr
|
||||
void NoteAllOverloadCandidates(Expr* E);
|
||||
|
||||
// [PossiblyAFunctionType] --> [Return]
|
||||
// NonFunctionType --> NonFunctionType
|
||||
// R (A) --> R(A)
|
||||
// R (*)(A) --> R (A)
|
||||
// R (&)(A) --> R (A)
|
||||
// R (S::*)(A) --> R (A)
|
||||
QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType);
|
||||
|
||||
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType,
|
||||
bool Complain,
|
||||
DeclAccessPair &Found);
|
||||
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
|
||||
|
||||
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From,
|
||||
bool Complain = false,
|
||||
DeclAccessPair* Found = 0);
|
||||
|
||||
Expr *FixOverloadedFunctionReference(Expr *E,
|
||||
DeclAccessPair FoundDecl,
|
||||
|
@ -3702,7 +3718,8 @@ public:
|
|||
SourceLocation Loc,
|
||||
const PartialDiagnostic &NoneDiag,
|
||||
const PartialDiagnostic &AmbigDiag,
|
||||
const PartialDiagnostic &CandidateDiag);
|
||||
const PartialDiagnostic &CandidateDiag,
|
||||
bool Complain = true);
|
||||
|
||||
ClassTemplatePartialSpecializationDecl *
|
||||
getMoreSpecializedPartialSpecialization(
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
using namespace clang;
|
||||
|
||||
|
||||
static void NoteAllOverloadCandidates(Expr* const Expr, Sema& sema);
|
||||
|
||||
enum TryCastResult {
|
||||
TC_NotApplicable, ///< The cast method is not applicable.
|
||||
|
@ -122,12 +121,24 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
|
|||
CXXCastPath &BasePath);
|
||||
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
|
||||
bool CStyle, unsigned &msg);
|
||||
static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
||||
static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
|
||||
QualType DestType, bool CStyle,
|
||||
const SourceRange &OpRange,
|
||||
unsigned &msg,
|
||||
CastKind &Kind);
|
||||
|
||||
|
||||
static ExprResult
|
||||
ResolveAndFixSingleFunctionTemplateSpecialization(
|
||||
Sema &Self, Expr *SrcExpr,
|
||||
bool DoFunctionPointerConverion = false,
|
||||
bool Complain = false,
|
||||
const SourceRange& OpRangeForComplaining = SourceRange(),
|
||||
QualType DestTypeForComplaining = QualType(),
|
||||
unsigned DiagIDForComplaining = 0);
|
||||
|
||||
|
||||
|
||||
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
|
||||
ExprResult
|
||||
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
||||
|
@ -583,7 +594,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload)
|
||||
<< OverloadExpr::find(SrcExpr).Expression->getName()
|
||||
<< DestType << OpRange;
|
||||
NoteAllOverloadCandidates(SrcExpr, Self);
|
||||
Self.NoteAllOverloadCandidates(SrcExpr);
|
||||
|
||||
} else {
|
||||
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr, DestType);
|
||||
|
@ -604,6 +615,19 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
|
||||
if (DestType->isVoidType()) {
|
||||
Self.IgnoredValueConversions(SrcExpr);
|
||||
if (SrcExpr->getType() == Self.Context.OverloadTy) {
|
||||
ExprResult SingleFunctionExpression =
|
||||
ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr,
|
||||
false, // Decay Function to ptr
|
||||
true, // Complain
|
||||
OpRange, DestType, diag::err_bad_static_cast_overload);
|
||||
if (SingleFunctionExpression.isUsable())
|
||||
{
|
||||
SrcExpr = SingleFunctionExpression.release();
|
||||
Kind = CK_ToVoid;
|
||||
}
|
||||
}
|
||||
else
|
||||
Kind = CK_ToVoid;
|
||||
return;
|
||||
}
|
||||
|
@ -614,13 +638,12 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
|
||||
unsigned msg = diag::err_bad_cxx_cast_generic;
|
||||
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
|
||||
Kind, BasePath) != TC_Success && msg != 0)
|
||||
{
|
||||
Kind, BasePath) != TC_Success && msg != 0) {
|
||||
if (SrcExpr->getType() == Self.Context.OverloadTy) {
|
||||
OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
|
||||
Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload)
|
||||
<< oe->getName() << DestType << OpRange << oe->getQualifierRange();
|
||||
NoteAllOverloadCandidates(SrcExpr, Self);
|
||||
Self.NoteAllOverloadCandidates(SrcExpr);
|
||||
} else {
|
||||
diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr, DestType);
|
||||
}
|
||||
|
@ -1236,32 +1259,44 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
|
|||
return TC_Success;
|
||||
}
|
||||
|
||||
// A helper function to resolve and fix an overloaded expression that
|
||||
// can be resolved because it identifies a single function
|
||||
// template specialization
|
||||
// Last three arguments should only be supplied if Complain = true
|
||||
static ExprResult ResolveAndFixSingleFunctionTemplateSpecialization(
|
||||
Sema &Self, Expr *SrcExpr,
|
||||
bool DoFunctionPointerConverion,
|
||||
bool Complain,
|
||||
const SourceRange& OpRangeForComplaining,
|
||||
QualType DestTypeForComplaining,
|
||||
unsigned DiagIDForComplaining) {
|
||||
assert(SrcExpr->getType() == Self.Context.OverloadTy);
|
||||
DeclAccessPair Found;
|
||||
bool ret = false;
|
||||
Expr* SingleFunctionExpression = 0;
|
||||
if (FunctionDecl* Fn = Self.ResolveSingleFunctionTemplateSpecialization(
|
||||
SrcExpr, false, // false -> Complain
|
||||
&Found)) {
|
||||
if (!Self.DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) {
|
||||
// mark the expression as resolved to Fn
|
||||
SingleFunctionExpression = Self.FixOverloadedFunctionReference(SrcExpr,
|
||||
Found, Fn);
|
||||
|
||||
static void NoteAllOverloadCandidates(Expr* const Expr, Sema& sema)
|
||||
{
|
||||
|
||||
assert(Expr->getType() == sema.Context.OverloadTy);
|
||||
|
||||
OverloadExpr::FindResult Ovl = OverloadExpr::find(Expr);
|
||||
OverloadExpr *const OvlExpr = Ovl.Expression;
|
||||
|
||||
for (UnresolvedSetIterator it = OvlExpr->decls_begin(),
|
||||
end = OvlExpr->decls_end(); it != end; ++it) {
|
||||
if ( FunctionTemplateDecl *ftd =
|
||||
dyn_cast<FunctionTemplateDecl>((*it)->getUnderlyingDecl()) )
|
||||
{
|
||||
sema.NoteOverloadCandidate(ftd->getTemplatedDecl());
|
||||
}
|
||||
else if ( FunctionDecl *f =
|
||||
dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl()) )
|
||||
{
|
||||
sema.NoteOverloadCandidate(f);
|
||||
if (DoFunctionPointerConverion)
|
||||
Self.DefaultFunctionArrayLvalueConversion(SingleFunctionExpression);
|
||||
}
|
||||
}
|
||||
if (!SingleFunctionExpression && Complain) {
|
||||
OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
|
||||
Self.Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
|
||||
<< oe->getName() << DestTypeForComplaining << OpRangeForComplaining
|
||||
<< oe->getQualifierRange();
|
||||
Self.NoteAllOverloadCandidates(SrcExpr);
|
||||
}
|
||||
return SingleFunctionExpression;
|
||||
}
|
||||
|
||||
|
||||
static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
||||
static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
|
||||
QualType DestType, bool CStyle,
|
||||
const SourceRange &OpRange,
|
||||
unsigned &msg,
|
||||
|
@ -1272,9 +1307,20 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
|||
QualType SrcType = SrcExpr->getType();
|
||||
|
||||
// Is the source an overloaded name? (i.e. &foo)
|
||||
// If so, reinterpret_cast can not help us here (13.4, p1, bullet 5)
|
||||
if (SrcType == Self.Context.OverloadTy)
|
||||
// If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ...
|
||||
if (SrcType == Self.Context.OverloadTy) {
|
||||
// ... unless foo<int> resolves to an lvalue unambiguously
|
||||
ExprResult SingleFunctionExpr =
|
||||
ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr,
|
||||
Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
|
||||
);
|
||||
if (SingleFunctionExpr.isUsable()) {
|
||||
SrcExpr = SingleFunctionExpr.release();
|
||||
SrcType = SrcExpr->getType();
|
||||
}
|
||||
else
|
||||
return TC_NotApplicable;
|
||||
}
|
||||
|
||||
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
|
||||
bool LValue = DestTypeTmp->isLValueReferenceType();
|
||||
|
@ -1495,8 +1541,24 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
|
|||
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
|
||||
if (CastTy->isVoidType()) {
|
||||
IgnoredValueConversions(CastExpr);
|
||||
bool ret = false; // false is 'able to convert'
|
||||
if (CastExpr->getType() == Context.OverloadTy) {
|
||||
ExprResult SingleFunctionExpr =
|
||||
ResolveAndFixSingleFunctionTemplateSpecialization(*this,
|
||||
CastExpr,
|
||||
/* Decay Function to ptr */ false,
|
||||
/* Complain */ true,
|
||||
R, CastTy, diag::err_bad_cstyle_cast_overload);
|
||||
if (SingleFunctionExpr.isUsable()) {
|
||||
CastExpr = SingleFunctionExpr.release();
|
||||
Kind = CK_ToVoid;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
Kind = CK_ToVoid;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Make sure we determine the value kind before we bail out for
|
||||
|
@ -1547,7 +1609,9 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
|
|||
CastTy,
|
||||
/* Complain */ true,
|
||||
Found);
|
||||
assert(!Fn && "cast failed but able to resolve overload expression!!");
|
||||
|
||||
assert(!Fn
|
||||
&& "cast failed but able to resolve overload expression!!");
|
||||
(void)Fn;
|
||||
|
||||
} else {
|
||||
|
|
|
@ -3190,7 +3190,10 @@ InitializationSequence::InitializationSequence(Sema &S,
|
|||
/*InOverloadResolution*/ false,
|
||||
/*CStyle=*/Kind.isCStyleOrFunctionalCast()))
|
||||
{
|
||||
if (Initializer->getType() == Context.OverloadTy)
|
||||
DeclAccessPair dap;
|
||||
if (Initializer->getType() == Context.OverloadTy &&
|
||||
!S.ResolveAddressOfOverloadedFunction(Initializer
|
||||
, DestType, false, dap))
|
||||
SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
|
||||
else
|
||||
SetFailed(InitializationSequence::FK_ConversionFailed);
|
||||
|
@ -4161,15 +4164,16 @@ bool InitializationSequence::Diagnose(Sema &S,
|
|||
<< Args[0]->getSourceRange();
|
||||
break;
|
||||
|
||||
case FK_ConversionFailed:
|
||||
case FK_ConversionFailed: {
|
||||
QualType FromType = Args[0]->getType();
|
||||
S.Diag(Kind.getLocation(), diag::err_init_conversion_failed)
|
||||
<< (int)Entity.getKind()
|
||||
<< DestType
|
||||
<< Args[0]->isLValue()
|
||||
<< Args[0]->getType()
|
||||
<< FromType
|
||||
<< Args[0]->getSourceRange();
|
||||
break;
|
||||
|
||||
}
|
||||
case FK_TooManyInitsForScalar: {
|
||||
SourceRange R;
|
||||
|
||||
|
|
|
@ -1036,6 +1036,21 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
|||
// We were able to resolve the address of the overloaded function,
|
||||
// so we can convert to the type of that function.
|
||||
FromType = Fn->getType();
|
||||
|
||||
// we can sometimes resolve &foo<int> regardless of ToType, so check
|
||||
// if the type matches (identity) or we are converting to bool
|
||||
if (!S.Context.hasSameUnqualifiedType(
|
||||
S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
|
||||
QualType resultTy;
|
||||
// if the function type matches except for [[noreturn]], it's ok
|
||||
if (!IsNoReturnConversion(S.Context, FromType,
|
||||
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
|
||||
// otherwise, only a boolean conversion is standard
|
||||
if (!ToType->isBooleanType())
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
|
||||
if (!Method->isStatic()) {
|
||||
const Type *ClassType
|
||||
|
@ -6349,6 +6364,27 @@ void Sema::NoteOverloadCandidate(FunctionDecl *Fn) {
|
|||
MaybeEmitInheritedConstructorNote(*this, Fn);
|
||||
}
|
||||
|
||||
//Notes the location of all overload candidates designated through
|
||||
// OverloadedExpr
|
||||
void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr) {
|
||||
assert(OverloadedExpr->getType() == Context.OverloadTy);
|
||||
|
||||
OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr);
|
||||
OverloadExpr *OvlExpr = Ovl.Expression;
|
||||
|
||||
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
|
||||
IEnd = OvlExpr->decls_end();
|
||||
I != IEnd; ++I) {
|
||||
if (FunctionTemplateDecl *FunTmpl =
|
||||
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
|
||||
NoteOverloadCandidate(FunTmpl->getTemplatedDecl());
|
||||
} else if (FunctionDecl *Fun
|
||||
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
|
||||
NoteOverloadCandidate(Fun);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Diagnoses an ambiguous conversion. The partial diagnostic is the
|
||||
/// "lead" diagnostic; it will be given two arguments, the source and
|
||||
/// target types of the conversion.
|
||||
|
@ -7049,110 +7085,117 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) {
|
|||
return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D);
|
||||
}
|
||||
|
||||
/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
|
||||
/// an overloaded function (C++ [over.over]), where @p From is an
|
||||
/// expression with overloaded function type and @p ToType is the type
|
||||
/// we're trying to resolve to. For example:
|
||||
///
|
||||
/// @code
|
||||
/// int f(double);
|
||||
/// int f(int);
|
||||
///
|
||||
/// int (*pfd)(double) = f; // selects f(double)
|
||||
/// @endcode
|
||||
///
|
||||
/// This routine returns the resulting FunctionDecl if it could be
|
||||
/// resolved, and NULL otherwise. When @p Complain is true, this
|
||||
/// routine will emit diagnostics if there is an error.
|
||||
FunctionDecl *
|
||||
Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
||||
bool Complain,
|
||||
DeclAccessPair &FoundResult) {
|
||||
QualType FunctionType = ToType;
|
||||
bool IsMember = false;
|
||||
if (const PointerType *ToTypePtr = ToType->getAs<PointerType>())
|
||||
FunctionType = ToTypePtr->getPointeeType();
|
||||
else if (const ReferenceType *ToTypeRef = ToType->getAs<ReferenceType>())
|
||||
FunctionType = ToTypeRef->getPointeeType();
|
||||
|
||||
|
||||
|
||||
// [PossiblyAFunctionType] --> [Return]
|
||||
// NonFunctionType --> NonFunctionType
|
||||
// R (A) --> R(A)
|
||||
// R (*)(A) --> R (A)
|
||||
// R (&)(A) --> R (A)
|
||||
// R (S::*)(A) --> R (A)
|
||||
QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) {
|
||||
QualType Ret = PossiblyAFunctionType;
|
||||
if (const PointerType *ToTypePtr =
|
||||
PossiblyAFunctionType->getAs<PointerType>())
|
||||
Ret = ToTypePtr->getPointeeType();
|
||||
else if (const ReferenceType *ToTypeRef =
|
||||
PossiblyAFunctionType->getAs<ReferenceType>())
|
||||
Ret = ToTypeRef->getPointeeType();
|
||||
else if (const MemberPointerType *MemTypePtr =
|
||||
ToType->getAs<MemberPointerType>()) {
|
||||
FunctionType = MemTypePtr->getPointeeType();
|
||||
IsMember = true;
|
||||
}
|
||||
PossiblyAFunctionType->getAs<MemberPointerType>())
|
||||
Ret = MemTypePtr->getPointeeType();
|
||||
Ret =
|
||||
Context.getCanonicalType(Ret).getUnqualifiedType();
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// C++ [over.over]p1:
|
||||
// [...] [Note: any redundant set of parentheses surrounding the
|
||||
// overloaded function name is ignored (5.1). ]
|
||||
// C++ [over.over]p1:
|
||||
// [...] The overloaded function name can be preceded by the &
|
||||
// operator.
|
||||
// However, remember whether the expression has member-pointer form:
|
||||
// C++ [expr.unary.op]p4:
|
||||
// A pointer to member is only formed when an explicit & is used
|
||||
// and its operand is a qualified-id not enclosed in
|
||||
// parentheses.
|
||||
OverloadExpr::FindResult Ovl = OverloadExpr::find(From);
|
||||
OverloadExpr *OvlExpr = Ovl.Expression;
|
||||
// A helper class to help with address of function resolution
|
||||
// - allows us to avoid passing around all those ugly parameters
|
||||
class AddressOfFunctionResolver
|
||||
{
|
||||
Sema& S;
|
||||
Expr* SourceExpr;
|
||||
const QualType& TargetType;
|
||||
QualType TargetFunctionType; // Extracted function type from target type
|
||||
|
||||
// We expect a pointer or reference to function, or a function pointer.
|
||||
FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
|
||||
if (!FunctionType->isFunctionType()) {
|
||||
if (Complain)
|
||||
Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref)
|
||||
<< OvlExpr->getName() << ToType;
|
||||
bool Complain;
|
||||
//DeclAccessPair& ResultFunctionAccessPair;
|
||||
ASTContext& Context;
|
||||
|
||||
return 0;
|
||||
}
|
||||
bool TargetTypeIsNonStaticMemberFunction;
|
||||
bool FoundNonTemplateFunction;
|
||||
|
||||
// If the overload expression doesn't have the form of a pointer to
|
||||
// member, don't try to convert it to a pointer-to-member type.
|
||||
if (IsMember && !Ovl.HasFormOfMemberPointer) {
|
||||
if (!Complain) return 0;
|
||||
|
||||
// TODO: Should we condition this on whether any functions might
|
||||
// have matched, or is it more appropriate to do that in callers?
|
||||
// TODO: a fixit wouldn't hurt.
|
||||
Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier)
|
||||
<< ToType << OvlExpr->getSourceRange();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0;
|
||||
if (OvlExpr->hasExplicitTemplateArgs()) {
|
||||
OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer);
|
||||
ExplicitTemplateArgs = &ETABuffer;
|
||||
}
|
||||
|
||||
assert(From->getType() == Context.OverloadTy);
|
||||
|
||||
// Look through all of the overloaded functions, searching for one
|
||||
// whose type matches exactly.
|
||||
OverloadExpr::FindResult OvlExprInfo;
|
||||
OverloadExpr *OvlExpr;
|
||||
TemplateArgumentListInfo OvlExplicitTemplateArgs;
|
||||
llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
|
||||
llvm::SmallVector<FunctionDecl *, 4> NonMatches;
|
||||
|
||||
bool FoundNonTemplateFunction = false;
|
||||
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
|
||||
E = OvlExpr->decls_end(); I != E; ++I) {
|
||||
// Look through any using declarations to find the underlying function.
|
||||
NamedDecl *Fn = (*I)->getUnderlyingDecl();
|
||||
public:
|
||||
AddressOfFunctionResolver(Sema &S, Expr* SourceExpr,
|
||||
const QualType& TargetType, bool Complain)
|
||||
: S(S), SourceExpr(SourceExpr), TargetType(TargetType),
|
||||
Complain(Complain), Context(S.getASTContext()),
|
||||
TargetTypeIsNonStaticMemberFunction(
|
||||
!!TargetType->getAs<MemberPointerType>()),
|
||||
FoundNonTemplateFunction(false),
|
||||
OvlExprInfo(OverloadExpr::find(SourceExpr)),
|
||||
OvlExpr(OvlExprInfo.Expression)
|
||||
{
|
||||
ExtractUnqualifiedFunctionTypeFromTargetType();
|
||||
|
||||
// C++ [over.over]p3:
|
||||
// Non-member functions and static member functions match
|
||||
// targets of type "pointer-to-function" or "reference-to-function."
|
||||
// Nonstatic member functions match targets of
|
||||
// type "pointer-to-member-function."
|
||||
// Note that according to DR 247, the containing class does not matter.
|
||||
if (!TargetFunctionType->isFunctionType()) {
|
||||
if (OvlExpr->hasExplicitTemplateArgs()) {
|
||||
DeclAccessPair dap;
|
||||
if( FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
|
||||
OvlExpr, false, &dap) ) {
|
||||
Matches.push_back(std::make_pair(dap,Fn));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (FunctionTemplateDecl *FunctionTemplate
|
||||
= dyn_cast<FunctionTemplateDecl>(Fn)) {
|
||||
if (OvlExpr->hasExplicitTemplateArgs())
|
||||
OvlExpr->getExplicitTemplateArgs().copyInto(OvlExplicitTemplateArgs);
|
||||
|
||||
if (FindAllFunctionsThatMatchTargetTypeExactly()) {
|
||||
// C++ [over.over]p4:
|
||||
// If more than one function is selected, [...]
|
||||
if (Matches.size() > 1) {
|
||||
if (FoundNonTemplateFunction)
|
||||
EliminateAllTemplateMatches();
|
||||
else
|
||||
EliminateAllExceptMostSpecializedTemplate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isTargetTypeAFunction() const {
|
||||
return TargetFunctionType->isFunctionType();
|
||||
}
|
||||
|
||||
// [ToType] [Return]
|
||||
|
||||
// R (*)(A) --> R (A), IsNonStaticMemberFunction = false
|
||||
// R (&)(A) --> R (A), IsNonStaticMemberFunction = false
|
||||
// R (S::*)(A) --> R (A), IsNonStaticMemberFunction = true
|
||||
void inline ExtractUnqualifiedFunctionTypeFromTargetType() {
|
||||
TargetFunctionType = S.ExtractUnqualifiedFunctionType(TargetType);
|
||||
}
|
||||
|
||||
// return true if any matching specializations were found
|
||||
bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate,
|
||||
const DeclAccessPair& CurAccessFunPair) {
|
||||
if (CXXMethodDecl *Method
|
||||
= dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
|
||||
// Skip non-static function templates when converting to pointer, and
|
||||
// static when converting to member pointer.
|
||||
if (Method->isStatic() == IsMember)
|
||||
continue;
|
||||
} else if (IsMember)
|
||||
continue;
|
||||
if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction)
|
||||
return false;
|
||||
}
|
||||
else if (TargetTypeIsNonStaticMemberFunction)
|
||||
return false;
|
||||
|
||||
// C++ [over.over]p2:
|
||||
// If the name is a function template, template argument deduction is
|
||||
|
@ -7162,73 +7205,87 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
|||
// overloaded functions considered.
|
||||
FunctionDecl *Specialization = 0;
|
||||
TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
|
||||
if (TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
|
||||
FunctionType, Specialization, Info)) {
|
||||
if (Sema::TemplateDeductionResult Result
|
||||
= S.DeduceTemplateArguments(FunctionTemplate,
|
||||
&OvlExplicitTemplateArgs,
|
||||
TargetFunctionType, Specialization,
|
||||
Info)) {
|
||||
// FIXME: make a note of the failed deduction for diagnostics.
|
||||
(void)Result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Template argument deduction ensures that we have an exact match.
|
||||
// This function template specicalization works.
|
||||
Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
|
||||
assert(FunctionType
|
||||
assert(TargetFunctionType
|
||||
== Context.getCanonicalType(Specialization->getType()));
|
||||
Matches.push_back(std::make_pair(I.getPair(), Specialization));
|
||||
}
|
||||
|
||||
continue;
|
||||
Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddMatchingNonTemplateFunction(NamedDecl* Fn,
|
||||
const DeclAccessPair& CurAccessFunPair) {
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
|
||||
// Skip non-static functions when converting to pointer, and static
|
||||
// when converting to member pointer.
|
||||
if (Method->isStatic() == IsMember)
|
||||
continue;
|
||||
|
||||
// If we have explicit template arguments, skip non-templates.
|
||||
if (OvlExpr->hasExplicitTemplateArgs())
|
||||
continue;
|
||||
} else if (IsMember)
|
||||
continue;
|
||||
if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction)
|
||||
return false;
|
||||
}
|
||||
else if (TargetTypeIsNonStaticMemberFunction)
|
||||
return false;
|
||||
|
||||
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) {
|
||||
QualType ResultTy;
|
||||
if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) ||
|
||||
IsNoReturnConversion(Context, FunDecl->getType(), FunctionType,
|
||||
if (Context.hasSameUnqualifiedType(TargetFunctionType,
|
||||
FunDecl->getType()) ||
|
||||
IsNoReturnConversion(Context, FunDecl->getType(), TargetFunctionType,
|
||||
ResultTy)) {
|
||||
Matches.push_back(std::make_pair(I.getPair(),
|
||||
Matches.push_back(std::make_pair(CurAccessFunPair,
|
||||
cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
|
||||
FoundNonTemplateFunction = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If there were 0 or 1 matches, we're done.
|
||||
if (Matches.empty()) {
|
||||
if (Complain) {
|
||||
Diag(From->getLocStart(), diag::err_addr_ovl_no_viable)
|
||||
<< OvlExpr->getName() << FunctionType;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FindAllFunctionsThatMatchTargetTypeExactly() {
|
||||
bool Ret = false;
|
||||
|
||||
// If the overload expression doesn't have the form of a pointer to
|
||||
// member, don't try to convert it to a pointer-to-member type.
|
||||
if (IsInvalidFormOfPointerToMemberFunction())
|
||||
return false;
|
||||
|
||||
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
|
||||
E = OvlExpr->decls_end();
|
||||
I != E; ++I)
|
||||
if (FunctionDecl *F = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
|
||||
NoteOverloadCandidate(F);
|
||||
I != E; ++I) {
|
||||
// Look through any using declarations to find the underlying function.
|
||||
NamedDecl *Fn = (*I)->getUnderlyingDecl();
|
||||
|
||||
// C++ [over.over]p3:
|
||||
// Non-member functions and static member functions match
|
||||
// targets of type "pointer-to-function" or "reference-to-function."
|
||||
// Nonstatic member functions match targets of
|
||||
// type "pointer-to-member-function."
|
||||
// Note that according to DR 247, the containing class does not matter.
|
||||
if (FunctionTemplateDecl *FunctionTemplate
|
||||
= dyn_cast<FunctionTemplateDecl>(Fn)) {
|
||||
if (AddMatchingTemplateFunction(FunctionTemplate, I.getPair()))
|
||||
Ret = true;
|
||||
}
|
||||
// If we have explicit template arguments supplied, skip non-templates.
|
||||
else if (!OvlExpr->hasExplicitTemplateArgs() &&
|
||||
AddMatchingNonTemplateFunction(Fn, I.getPair()))
|
||||
Ret = true;
|
||||
}
|
||||
assert(Ret || Matches.empty());
|
||||
return Ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if (Matches.size() == 1) {
|
||||
FunctionDecl *Result = Matches[0].second;
|
||||
FoundResult = Matches[0].first;
|
||||
MarkDeclarationReferenced(From->getLocStart(), Result);
|
||||
if (Complain) {
|
||||
CheckAddressOfMemberAccess(OvlExpr, Matches[0].first);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
// C++ [over.over]p4:
|
||||
// If more than one function is selected, [...]
|
||||
if (!FoundNonTemplateFunction) {
|
||||
void EliminateAllExceptMostSpecializedTemplate() {
|
||||
// [...] and any given function template specialization F1 is
|
||||
// eliminated if the set contains a second function template
|
||||
// specialization whose function template is more specialized
|
||||
|
@ -7245,23 +7302,24 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
|||
MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess());
|
||||
|
||||
UnresolvedSetIterator Result =
|
||||
getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(),
|
||||
TPOC_Other, 0, From->getLocStart(),
|
||||
PDiag(),
|
||||
PDiag(diag::err_addr_ovl_ambiguous)
|
||||
S.getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(),
|
||||
TPOC_Other, 0, SourceExpr->getLocStart(),
|
||||
S.PDiag(),
|
||||
S.PDiag(diag::err_addr_ovl_ambiguous)
|
||||
<< Matches[0].second->getDeclName(),
|
||||
PDiag(diag::note_ovl_candidate)
|
||||
<< (unsigned) oc_function_template);
|
||||
if (Result == MatchesCopy.end())
|
||||
return 0;
|
||||
S.PDiag(diag::note_ovl_candidate)
|
||||
<< (unsigned) oc_function_template,
|
||||
Complain);
|
||||
|
||||
MarkDeclarationReferenced(From->getLocStart(), *Result);
|
||||
FoundResult = Matches[Result - MatchesCopy.begin()].first;
|
||||
if (Complain)
|
||||
CheckUnresolvedAccess(*this, OvlExpr, FoundResult);
|
||||
return cast<FunctionDecl>(*Result);
|
||||
if (Result != MatchesCopy.end()) {
|
||||
// Make it the first and only element
|
||||
Matches[0].first = Matches[Result - MatchesCopy.begin()].first;
|
||||
Matches[0].second = cast<FunctionDecl>(*Result);
|
||||
Matches.resize(1);
|
||||
}
|
||||
}
|
||||
|
||||
void EliminateAllTemplateMatches() {
|
||||
// [...] any function template specializations in the set are
|
||||
// eliminated if the set also contains a non-template function, [...]
|
||||
for (unsigned I = 0, N = Matches.size(); I != N; ) {
|
||||
|
@ -7272,27 +7330,99 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
|||
Matches.set_size(N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [...] After such eliminations, if any, there shall remain exactly one
|
||||
// selected function.
|
||||
if (Matches.size() == 1) {
|
||||
MarkDeclarationReferenced(From->getLocStart(), Matches[0].second);
|
||||
FoundResult = Matches[0].first;
|
||||
public:
|
||||
void ComplainNoMatchesFound() const {
|
||||
assert(Matches.empty());
|
||||
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_no_viable)
|
||||
<< OvlExpr->getName() << TargetFunctionType
|
||||
<< OvlExpr->getSourceRange();
|
||||
S.NoteAllOverloadCandidates(OvlExpr);
|
||||
}
|
||||
|
||||
bool IsInvalidFormOfPointerToMemberFunction() const {
|
||||
return TargetTypeIsNonStaticMemberFunction &&
|
||||
!OvlExprInfo.HasFormOfMemberPointer;
|
||||
}
|
||||
|
||||
void ComplainIsInvalidFormOfPointerToMemberFunction() const {
|
||||
// TODO: Should we condition this on whether any functions might
|
||||
// have matched, or is it more appropriate to do that in callers?
|
||||
// TODO: a fixit wouldn't hurt.
|
||||
S.Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier)
|
||||
<< TargetType << OvlExpr->getSourceRange();
|
||||
}
|
||||
|
||||
void ComplainOfInvalidConversion() const {
|
||||
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_not_func_ptrref)
|
||||
<< OvlExpr->getName() << TargetType;
|
||||
}
|
||||
|
||||
void ComplainMultipleMatchesFound() const {
|
||||
assert(Matches.size() > 1);
|
||||
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_ambiguous)
|
||||
<< OvlExpr->getName()
|
||||
<< OvlExpr->getSourceRange();
|
||||
S.NoteAllOverloadCandidates(OvlExpr);
|
||||
}
|
||||
|
||||
int getNumMatches() const { return Matches.size(); }
|
||||
|
||||
FunctionDecl* getMatchingFunctionDecl() const {
|
||||
if (Matches.size() != 1) return 0;
|
||||
return Matches[0].second;
|
||||
}
|
||||
|
||||
const DeclAccessPair* getMatchingFunctionAccessPair() const {
|
||||
if (Matches.size() != 1) return 0;
|
||||
return &Matches[0].first;
|
||||
}
|
||||
};
|
||||
|
||||
/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
|
||||
/// an overloaded function (C++ [over.over]), where @p From is an
|
||||
/// expression with overloaded function type and @p ToType is the type
|
||||
/// we're trying to resolve to. For example:
|
||||
///
|
||||
/// @code
|
||||
/// int f(double);
|
||||
/// int f(int);
|
||||
///
|
||||
/// int (*pfd)(double) = f; // selects f(double)
|
||||
/// @endcode
|
||||
///
|
||||
/// This routine returns the resulting FunctionDecl if it could be
|
||||
/// resolved, and NULL otherwise. When @p Complain is true, this
|
||||
/// routine will emit diagnostics if there is an error.
|
||||
FunctionDecl *
|
||||
Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType,
|
||||
bool Complain,
|
||||
DeclAccessPair &FoundResult) {
|
||||
|
||||
assert(AddressOfExpr->getType() == Context.OverloadTy);
|
||||
|
||||
AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType, Complain);
|
||||
int NumMatches = Resolver.getNumMatches();
|
||||
FunctionDecl* Fn = 0;
|
||||
if ( NumMatches == 0 && Complain) {
|
||||
if (Resolver.IsInvalidFormOfPointerToMemberFunction())
|
||||
Resolver.ComplainIsInvalidFormOfPointerToMemberFunction();
|
||||
else
|
||||
Resolver.ComplainNoMatchesFound();
|
||||
}
|
||||
else if (NumMatches > 1 && Complain)
|
||||
Resolver.ComplainMultipleMatchesFound();
|
||||
else if (NumMatches == 1) {
|
||||
Fn = Resolver.getMatchingFunctionDecl();
|
||||
assert(Fn);
|
||||
FoundResult = *Resolver.getMatchingFunctionAccessPair();
|
||||
MarkDeclarationReferenced(AddressOfExpr->getLocStart(), Fn);
|
||||
if (Complain)
|
||||
CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
|
||||
return cast<FunctionDecl>(Matches[0].second);
|
||||
CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
|
||||
}
|
||||
|
||||
// FIXME: We should probably return the same thing that BestViableFunction
|
||||
// returns (even if we issue the diagnostics here).
|
||||
if (Complain) {
|
||||
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
|
||||
<< Matches[0].second->getDeclName();
|
||||
for (unsigned I = 0, E = Matches.size(); I != E; ++I)
|
||||
NoteOverloadCandidate(Matches[I].second);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return Fn;
|
||||
}
|
||||
|
||||
/// \brief Given an expression that refers to an overloaded function, try to
|
||||
|
@ -7302,14 +7432,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
|||
/// 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) {
|
||||
FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From,
|
||||
bool Complain,
|
||||
DeclAccessPair* FoundResult) {
|
||||
// C++ [over.over]p1:
|
||||
// [...] [Note: any redundant set of parentheses surrounding the
|
||||
// overloaded function name is ignored (5.1). ]
|
||||
// C++ [over.over]p1:
|
||||
// [...] The overloaded function name can be preceded by the &
|
||||
// operator.
|
||||
|
||||
if (From->getType() != Context.OverloadTy)
|
||||
return 0;
|
||||
|
||||
|
@ -7353,10 +7484,20 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
|
|||
}
|
||||
|
||||
// Multiple matches; we can't resolve to a single declaration.
|
||||
if (Matched)
|
||||
return 0;
|
||||
if (Matched) {
|
||||
if (FoundResult)
|
||||
*FoundResult = DeclAccessPair();
|
||||
|
||||
Matched = Specialization;
|
||||
if (Complain) {
|
||||
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
|
||||
<< OvlExpr->getName();
|
||||
NoteAllOverloadCandidates(OvlExpr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((Matched = Specialization) && FoundResult)
|
||||
*FoundResult = I.getPair();
|
||||
}
|
||||
|
||||
return Matched;
|
||||
|
|
|
@ -1824,6 +1824,11 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
|
|||
// template arguments that we have against the template name, if the template
|
||||
// name refers to a single template. That's not a terribly common case,
|
||||
// though.
|
||||
// foo<int> could identify a single function unambiguously
|
||||
// This approach does NOT work, since f<int>(1);
|
||||
// gets resolved prior to resorting to overload resolution
|
||||
// i.e., template<class T> void f(double);
|
||||
// vs template<class T, class U> void f(U);
|
||||
|
||||
// These should be filtered out by our callers.
|
||||
assert(!R.empty() && "empty lookup results when building templateid");
|
||||
|
|
|
@ -3322,8 +3322,10 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
|
|||
SourceLocation Loc,
|
||||
const PartialDiagnostic &NoneDiag,
|
||||
const PartialDiagnostic &AmbigDiag,
|
||||
const PartialDiagnostic &CandidateDiag) {
|
||||
const PartialDiagnostic &CandidateDiag,
|
||||
bool Complain) {
|
||||
if (SpecBegin == SpecEnd) {
|
||||
if (Complain)
|
||||
Diag(Loc, NoneDiag);
|
||||
return SpecEnd;
|
||||
}
|
||||
|
@ -3370,8 +3372,10 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
|
|||
}
|
||||
|
||||
// Diagnose the ambiguity.
|
||||
if (Complain)
|
||||
Diag(Loc, AmbigDiag);
|
||||
|
||||
if (Complain)
|
||||
// FIXME: Can we order the candidates in some sane way?
|
||||
for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I)
|
||||
Diag((*I)->getLocation(), CandidateDiag)
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
|
||||
|
||||
namespace DontResolveTooEarly_WaitForOverloadResolution
|
||||
{
|
||||
template <class T> T* f(int); // #1
|
||||
template <class T, class U> T& f(U); // #2
|
||||
|
||||
void g() {
|
||||
int *ip = f<int>(1); // calls #1
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* f2(int);
|
||||
template <class T, class U>
|
||||
T& f2(U);
|
||||
|
||||
void g2() {
|
||||
int*ip = (f2<int>)(1); // ok
|
||||
}
|
||||
|
||||
} // End namespace
|
||||
|
||||
template<typename T>
|
||||
void twoT() { }
|
||||
template<typename T, typename U>
|
||||
void twoT(T) { }
|
||||
|
||||
|
||||
void two() { }; //expected-note 5{{candidate}}
|
||||
void two(int) { }; //expected-note 5{{candidate}}
|
||||
|
||||
|
||||
|
||||
void one() { }
|
||||
template<class T>
|
||||
void oneT() { }
|
||||
|
||||
template<class T>
|
||||
void cant_resolve() { } //expected-note 3{{candidate}}
|
||||
|
||||
template<class T> void cant_resolve(T) { }//expected-note 3{{candidate}}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
{ static_cast<void>(one); }
|
||||
{ (void)(one); }
|
||||
{ static_cast<void>(oneT<int>); }
|
||||
{ (void)(oneT<int>); }
|
||||
|
||||
{ static_cast<void>(two); } // expected-error {{address of overloaded}}
|
||||
{ (void)(two); } // expected-error {{address of overloaded}}
|
||||
{ static_cast<void>(twoT<int>); }
|
||||
{ (void)(twoT<int>); }
|
||||
|
||||
|
||||
{ ptrdiff_t x = reinterpret_cast<ptrdiff_t>(oneT<int>); }
|
||||
{ (void) reinterpret_cast<int (*)(char, double)>(oneT<int>); }
|
||||
{ (void) reinterpret_cast<ptrdiff_t>(one); }
|
||||
{ (void) reinterpret_cast<int (*)(char, double)>(one); }
|
||||
|
||||
{ ptrdiff_t x = reinterpret_cast<ptrdiff_t>(twoT<int>); }
|
||||
{ (void) reinterpret_cast<int (*)(char, double)>(twoT<int>); }
|
||||
{ (void) reinterpret_cast<void (*)(int)>(two); } //expected-error {{reinterpret_cast}}
|
||||
{ (void) static_cast<void (*)(int)>(two); } //ok
|
||||
|
||||
{ (void) reinterpret_cast<int>(two); } //expected-error {{reinterpret_cast}}
|
||||
{ (void) reinterpret_cast<int (*)(char, double)>(two); } //expected-error {{reinterpret_cast}}
|
||||
|
||||
{ bool b = (twoT<int>); } // ok
|
||||
{ bool b = (twoT<int, int>); } //ok
|
||||
|
||||
{ bool b = &twoT<int>; //&foo<int>; }
|
||||
b = &(twoT<int>); }
|
||||
|
||||
{ ptrdiff_t x = (ptrdiff_t) &twoT<int>;
|
||||
x = (ptrdiff_t) &twoT<int>; }
|
||||
|
||||
{ ptrdiff_t x = (ptrdiff_t) twoT<int>;
|
||||
x = (ptrdiff_t) twoT<int>; }
|
||||
|
||||
|
||||
{ ptrdiff_t x = (ptrdiff_t) &twoT<int,int>;
|
||||
x = (ptrdiff_t) &twoT<int>; }
|
||||
|
||||
{ oneT<int>; &oneT<int>; } //expected-warning 2{{ expression result unused }}
|
||||
{ static_cast<void>(cant_resolve<int>); } // expected-error {{address of overload}}
|
||||
{ bool b = cant_resolve<int>; } // expected-error {{address of overload}}
|
||||
{ (void) cant_resolve<int>; } // expected-error {{address of overload}}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
template<typename T> T f0(T, T);
|
||||
template<typename T> T f0(T, T); //expected-note{{candidate}}
|
||||
|
||||
void test_f0() {
|
||||
int (*f0a)(int, int) = f0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
template<typename T> T f0(T);
|
||||
template<typename T> T f0(T); // expected-note{{candidate function}}
|
||||
int f0(int); // expected-note{{candidate function}}
|
||||
|
||||
void test_f0() {
|
||||
|
@ -13,8 +13,6 @@ namespace N {
|
|||
int f0(int); // expected-note{{candidate function}}
|
||||
}
|
||||
|
||||
int f0(int);
|
||||
|
||||
void test_f0_2() {
|
||||
using namespace N;
|
||||
int (*fp0)(int) = f0; // expected-error{{address of overloaded function 'f0' is ambiguous}}
|
||||
|
|
|
@ -4,8 +4,8 @@ void g();
|
|||
void f(); // expected-note 9{{candidate function}}
|
||||
void f(int); // expected-note 9{{candidate function}}
|
||||
|
||||
template<class T> void t(T); // expected-note 3{{candidate function}}
|
||||
template<class T> void t(T*); // expected-note 3{{candidate function}}
|
||||
template<class T> void t(T); // expected-note 6{{candidate function}}
|
||||
template<class T> void t(T*); // expected-note 6{{candidate function}}
|
||||
|
||||
template<class T> void u(T);
|
||||
|
||||
|
|
|
@ -57,11 +57,11 @@ struct B
|
|||
|
||||
struct C {
|
||||
C &getC() {
|
||||
return makeAC; // expected-error{{address of overloaded function 'makeAC' cannot be converted to type 'C'}}
|
||||
return makeAC; // expected-error{{address of overloaded function 'makeAC'}}
|
||||
}
|
||||
|
||||
C &makeAC();
|
||||
const C &makeAC() const;
|
||||
C &makeAC(); //expected-note{{candidate function}}
|
||||
const C &makeAC() const; //expected-note{{candidate function}}
|
||||
|
||||
static void f(); // expected-note{{candidate function}}
|
||||
static void f(int); // expected-note{{candidate function}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче