CanQualType FloatTy, DoubleTy, LongDoubleTy;
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
- CanQualType OverloadTy, DependentTy, UnknownAnyTy;
+ CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
/// \brief Returns true if this expression is a bound member function.
bool isBoundMemberFunction(ASTContext &Ctx) const;
+ /// \brief Given an expression of bound-member type, find the type
+ /// of the member. Returns null if this is an *overloaded* bound
+ /// member expression.
+ static QualType findBoundMemberType(const Expr *expr);
+
/// \brief Result type of CanThrow().
enum CanThrowResult {
CT_Cannot,
/// BuiltinTypes.
bool isPlaceholderType() const;
+ /// isSpecificPlaceholderType - Test for a specific placeholder type.
+ bool isSpecificPlaceholderType(unsigned K) const;
+
/// isIntegerType() does *not* include complex integers (a GCC extension).
/// isComplexIntegerType() can be used to test for complex integers.
bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
NullPtr, // This is the type of C++0x 'nullptr'.
+ /// The primitive Objective C 'id' type. The user-visible 'id'
+ /// type is a typedef of an ObjCObjectPointerType to an
+ /// ObjCObjectType with this as its base. In fact, this only ever
+ /// shows up in an AST as the base type of an ObjCObjectType.
+ ObjCId,
+
+ /// The primitive Objective C 'Class' type. The user-visible
+ /// 'Class' type is a typedef of an ObjCObjectPointerType to an
+ /// ObjCObjectType with this as its base. In fact, this only ever
+ /// shows up in an AST as the base type of an ObjCObjectType.
+ ObjCClass,
+
+ /// The primitive Objective C 'SEL' type. The user-visible 'SEL'
+ /// type is a typedef of a PointerType to this.
+ ObjCSel,
+
/// This represents the type of an expression whose type is
/// totally unknown, e.g. 'T::foo'. It is permitted for this to
/// appear in situations where the structure of the type is
/// theoretically deducible.
Dependent,
- /// The type of an unresolved overload set.
+ /// The type of an unresolved overload set. A placeholder type.
+ /// Expressions with this type have one of the following basic
+ /// forms, with parentheses generally permitted:
+ /// foo # possibly qualified, not if an implicit access
+ /// foo # possibly qualified, not if an implicit access
+ /// &foo # possibly qualified, not if an implicit access
+ /// x->foo # only if might be a static member function
+ /// &x->foo # only if might be a static member function
+ /// &Class::foo # when a pointer-to-member; sub-expr also has this type
+ /// OverloadExpr::find can be used to analyze the expression.
Overload,
- /// __builtin_any_type. Useful for clients like debuggers
- /// that don't know what type to give something. Only a small
- /// number of operations are valid on expressions of unknown type;
- /// notable among them, calls and explicit casts.
- UnknownAny,
-
- /// The primitive Objective C 'id' type. The type pointed to by the
- /// user-visible 'id' type. Only ever shows up in an AST as the base
- /// type of an ObjCObjectType.
- ObjCId,
-
- /// The primitive Objective C 'Class' type. The type pointed to by the
- /// user-visible 'Class' type. Only ever shows up in an AST as the
- /// base type of an ObjCObjectType.
- ObjCClass,
-
- ObjCSel // This represents the ObjC 'SEL' type.
+ /// The type of a bound C++ non-static member function.
+ /// A placeholder type. Expressions with this type have one of the
+ /// following basic forms:
+ /// foo # if an implicit access
+ /// x->foo # if only contains non-static members
+ BoundMember,
+
+ /// __builtin_any_type. A placeholder type. Useful for clients
+ /// like debuggers that don't know what type to give something.
+ /// Only a small number of operations are valid on expressions of
+ /// unknown type, most notably explicit casts.
+ UnknownAny
};
public:
return getKind() >= Float && getKind() <= LongDouble;
}
- /// Determines whether this type is a "forbidden" placeholder type,
- /// i.e. a type which cannot appear in arbitrary positions in a
- /// fully-formed expression.
+ /// Determines whether this type is a placeholder type, i.e. a type
+ /// which cannot appear in arbitrary positions in a fully-formed
+ /// expression.
bool isPlaceholderType() const {
- return getKind() == Overload || getKind() == UnknownAny;
+ return getKind() >= Overload;
}
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
return false;
}
+inline bool Type::isSpecificPlaceholderType(unsigned K) const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
+ return (BT->getKind() == (BuiltinType::Kind) K);
+ return false;
+}
+
/// \brief Determines whether this is a type for which one can define
/// an overloaded operator.
inline bool Type::isOverloadableType() const {
class ObjCPropertyDecl;
class ObjCProtocolDecl;
class OverloadCandidateSet;
+ class OverloadExpr;
class ParenListExpr;
class ParmVarDecl;
class Preprocessor;
bool Complain,
DeclAccessPair &Found);
- FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From,
+ FunctionDecl *ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
bool Complain = false,
DeclAccessPair* Found = 0);
PREDEF_TYPE_OBJC_CLASS = 27,
/// \brief The ObjC 'SEL' type.
PREDEF_TYPE_OBJC_SEL = 28,
- /// \brief The 'unknown any' type.
- PREDEF_TYPE_UNKNOWN_ANY = 29
+ /// \brief The 'unknown any' placeholder type.
+ PREDEF_TYPE_UNKNOWN_ANY = 29,
+ /// \brief The placeholder type for bound member functions.
+ PREDEF_TYPE_BOUND_MEMBER = 30
};
/// \brief The number of predefined type IDs that are reserved for
// Placeholder type for functions.
InitBuiltinType(OverloadTy, BuiltinType::Overload);
+ // Placeholder type for bound members.
+ InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember);
+
// "any" type; useful for debugger-like clients.
InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny);
case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
case BuiltinType::UnknownAny: return Importer.getToContext().UnknownAnyTy;
+ case BuiltinType::BoundMember: return Importer.getToContext().BoundMemberTy;
case BuiltinType::ObjCId:
// FIXME: Make sure that the "to" context supports Objective-C!
CalleeType = FnTypePtr->getPointeeType();
else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>())
CalleeType = BPT->getPointeeType();
- else if (const MemberPointerType *MPT
- = CalleeType->getAs<MemberPointerType>())
- CalleeType = MPT->getPointeeType();
+ else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember))
+ // This should never be overloaded and so should never return null.
+ CalleeType = Expr::findBoundMemberType(getCallee());
- const FunctionType *FnType = CalleeType->getAs<FunctionType>();
+ const FunctionType *FnType = CalleeType->castAs<FunctionType>();
return FnType->getResultType();
}
return ClassifyLValue(Ctx) == Expr::LV_MemberFunction;
}
+QualType Expr::findBoundMemberType(const Expr *expr) {
+ assert(expr->getType()->isSpecificPlaceholderType(BuiltinType::BoundMember));
+
+ // Bound member expressions are always one of these possibilities:
+ // x->m x.m x->*y x.*y
+ // (possibly parenthesized)
+
+ expr = expr->IgnoreParens();
+ if (const MemberExpr *mem = dyn_cast<MemberExpr>(expr)) {
+ assert(isa<CXXMethodDecl>(mem->getMemberDecl()));
+ return mem->getMemberDecl()->getType();
+ }
+
+ if (const BinaryOperator *op = dyn_cast<BinaryOperator>(expr)) {
+ QualType type = op->getRHS()->getType()->castAs<MemberPointerType>()
+ ->getPointeeType();
+ assert(type->isFunctionType());
+ return type;
+ }
+
+ assert(isa<UnresolvedMemberExpr>(expr));
+ return QualType();
+}
+
static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,
Expr::CanThrowResult CT2) {
// CanThrowResult constants are ordered so that the maximum is the correct
return cast<Expr>(Base)->isImplicitCXXThis();
}
+static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin,
+ UnresolvedSetIterator end) {
+ do {
+ NamedDecl *decl = *begin;
+ if (isa<UnresolvedUsingValueDecl>(decl))
+ return false;
+ if (isa<UsingShadowDecl>(decl))
+ decl = cast<UsingShadowDecl>(decl)->getUnderlyingDecl();
+
+ // Unresolved member expressions should only contain methods and
+ // method templates.
+ assert(isa<CXXMethodDecl>(decl) || isa<FunctionTemplateDecl>(decl));
+
+ if (isa<FunctionTemplateDecl>(decl))
+ decl = cast<FunctionTemplateDecl>(decl)->getTemplatedDecl();
+ if (cast<CXXMethodDecl>(decl)->isStatic())
+ return false;
+ } while (++begin != end);
+
+ return true;
+}
+
UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType,
BaseType->containsUnexpandedParameterPack())),
IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) {
+
+ // Check whether all of the members are non-static member functions,
+ // and if so, mark give this bound-member type instead of overload type.
+ if (hasOnlyNonStaticMemberFunctions(Begin, End))
+ setType(C.BoundMemberTy);
}
bool UnresolvedMemberExpr::isImplicitAccess() const {
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::BoundMember:
case BuiltinType::UnknownAny:
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
case BuiltinType::Overload:
case BuiltinType::Dependent:
case BuiltinType::UnknownAny:
+ case BuiltinType::BoundMember:
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
case Char32: return "char32_t";
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
+ case BoundMember: return "<bound member function type>";
case Dependent: return "<dependent type>";
case UnknownAny: return "<unknown type>";
case ObjCId: return "id";
case BuiltinType::NullPtr:
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::BoundMember:
case BuiltinType::UnknownAny:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
const Expr *MemFnExpr = BO->getRHS();
const MemberPointerType *MPT =
- MemFnExpr->getType()->getAs<MemberPointerType>();
+ MemFnExpr->getType()->castAs<MemberPointerType>();
const FunctionProtoType *FPT =
- MPT->getPointeeType()->getAs<FunctionProtoType>();
+ MPT->getPointeeType()->castAs<FunctionProtoType>();
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
- const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>();
- return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee,
+ return EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee,
ReturnValue, Args);
}
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::BoundMember:
case BuiltinType::UnknownAny:
- assert(false && "Should not see this type here!");
+ llvm_unreachable("asking for RRTI for a placeholder type!");
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
- assert(false && "Non-canonical or dependent types aren't possible.");
+ llvm_unreachable("Non-canonical or dependent types aren't possible.");
break;
case Type::Builtin: {
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::BoundMember:
case BuiltinType::UnknownAny:
- llvm_unreachable("Unexpected builtin type!");
+ llvm_unreachable("Unexpected placeholder builtin type!");
break;
}
llvm_unreachable("Unknown builtin type!");
// FIXME: should we check this in a more fine-grained manner?
bool TypeDependent = DestType->isDependentType() || Ex.get()->isTypeDependent();
- if (Ex.get()->isBoundMemberFunction(Context))
- Diag(Ex.get()->getLocStart(), diag::err_invalid_use_of_bound_member_func)
- << Ex.get()->getSourceRange();
-
ExprValueKind VK = VK_RValue;
if (TypeDependent)
VK = Expr::getValueKindForType(DestType);
/// Diagnose a failed cast.
static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
SourceRange opRange, Expr *src, QualType destType) {
+ if (src->getType() == S.Context.BoundMemberTy) {
+ (void) S.CheckPlaceholderExpr(src); // will always fail
+ return;
+ }
+
if (msg == diag::err_bad_cxx_cast_generic &&
tryDiagnoseOverloadedCast(S, castType, opRange, src, destType))
return;
Expr *CastExpr, CastKind &Kind,
CXXCastPath &BasePath,
bool FunctionalStyle) {
- if (CastExpr->isBoundMemberFunction(Context)) {
- Diag(CastExpr->getLocStart(), diag::err_invalid_use_of_bound_member_func)
- << CastExpr->getSourceRange();
- return ExprError();
- }
-
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
return ExprError();
CastExpr = CastExprRes.take();
+ if (CastExpr->getType() == Context.BoundMemberTy)
+ return CheckPlaceholderExpr(CastExpr); // will always fail
+
if (CastExpr->getType() == Context.OverloadTy) {
ExprResult SingleFunctionExpr =
ResolveAndFixSingleFunctionTemplateSpecialization(
}
if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ ExprValueKind valueKind;
+ QualType type;
+ if (MemberFn->isInstance()) {
+ valueKind = VK_RValue;
+ type = Context.BoundMemberTy;
+ } else {
+ valueKind = VK_LValue;
+ type = MemberFn->getType();
+ }
+
MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
MemberFn, FoundDecl, MemberNameInfo,
- MemberFn->getType(),
- MemberFn->isInstance() ? VK_RValue : VK_LValue,
- OK_Ordinary));
+ type, valueKind, OK_Ordinary));
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, ".");
IsArrow = false;
+ } else if (BaseType == Context.BoundMemberTy) {
+ goto fail;
} else {
Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
<< BaseType << BaseExpr.get()->getSourceRange();
}
} else if ((Fun = BaseType->getAs<FunctionType>())) {
TryCall = true;
+ } else if (BaseType == Context.BoundMemberTy) {
+ // Look for the bound-member type. If it's still overloaded,
+ // give up, although we probably should have fallen into the
+ // OverloadExpr case above if we actually have an overloaded
+ // bound member.
+ QualType fnType = Expr::findBoundMemberType(BaseExpr.get());
+ if (!fnType.isNull()) {
+ TryCall = true;
+ Fun = fnType->castAs<FunctionType>();
+ }
}
if (TryCall) {
Fn = result.take();
}
- Expr *NakedFn = Fn->IgnoreParens();
-
- // Determine whether this is a call to an unresolved member function.
- if (UnresolvedMemberExpr *MemE = dyn_cast<UnresolvedMemberExpr>(NakedFn)) {
- // If lookup was unresolved but not dependent (i.e. didn't find
- // an unresolved using declaration), it has to be an overloaded
- // function set, which means it must contain either multiple
- // declarations (all methods or method templates) or a single
- // method template.
- assert((MemE->getNumDecls() > 1) ||
- isa<FunctionTemplateDecl>(
- (*MemE->decls_begin())->getUnderlyingDecl()));
- (void)MemE;
-
+ if (Fn->getType() == Context.BoundMemberTy) {
return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
RParenLoc);
}
+ }
+
+ // Check for overloaded calls. This can happen even in C due to extensions.
+ if (Fn->getType() == Context.OverloadTy) {
+ OverloadExpr::FindResult find = OverloadExpr::find(Fn);
- // Determine whether this is a call to a member function.
- if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) {
- NamedDecl *MemDecl = MemExpr->getMemberDecl();
- if (isa<CXXMethodDecl>(MemDecl))
+ // We aren't supposed to apply this logic if there's an '&' involved.
+ if (!find.IsAddressOfOperand) {
+ OverloadExpr *ovl = find.Expression;
+ if (isa<UnresolvedLookupExpr>(ovl)) {
+ UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl);
+ return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs,
+ RParenLoc, ExecConfig);
+ } else {
return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
RParenLoc);
- }
-
- // Determine whether this is a call to a pointer-to-member function.
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(NakedFn)) {
- if (BO->getOpcode() == BO_PtrMemD ||
- BO->getOpcode() == BO_PtrMemI) {
- if (const FunctionProtoType *FPT
- = BO->getType()->getAs<FunctionProtoType>()) {
- QualType ResultTy = FPT->getCallResultType(Context);
- ExprValueKind VK = Expr::getValueKindForType(FPT->getResultType());
-
- // Check that the object type isn't more qualified than the
- // member function we're calling.
- Qualifiers FuncQuals = Qualifiers::fromCVRMask(FPT->getTypeQuals());
- Qualifiers ObjectQuals
- = BO->getOpcode() == BO_PtrMemD
- ? BO->getLHS()->getType().getQualifiers()
- : BO->getLHS()->getType()->getAs<PointerType>()
- ->getPointeeType().getQualifiers();
-
- Qualifiers Difference = ObjectQuals - FuncQuals;
- Difference.removeObjCGCAttr();
- Difference.removeAddressSpace();
- if (Difference) {
- std::string QualsString = Difference.getAsString();
- Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals)
- << BO->getType().getUnqualifiedType()
- << QualsString
- << (QualsString.find(' ') == std::string::npos? 1 : 2);
- }
-
- CXXMemberCallExpr *TheCall
- = new (Context) CXXMemberCallExpr(Context, Fn, Args,
- NumArgs, ResultTy, VK,
- RParenLoc);
-
- if (CheckCallReturnType(FPT->getResultType(),
- BO->getRHS()->getSourceRange().getBegin(),
- TheCall, 0))
- return ExprError();
-
- if (ConvertArgumentsForCall(TheCall, BO, 0, FPT, Args, NumArgs,
- RParenLoc))
- return ExprError();
-
- return MaybeBindToTemporary(TheCall);
- }
}
}
}
// If we're directly calling a function, get the appropriate declaration.
- // Also, in C++, keep track of whether we should perform argument-dependent
- // lookup and whether there were any explicitly-specified template arguments.
Expr *NakedFn = Fn->IgnoreParens();
- if (isa<UnresolvedLookupExpr>(NakedFn)) {
- UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn);
- return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs,
- RParenLoc, ExecConfig);
- }
NamedDecl *NDecl = 0;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn))
if (isa<DeclRefExpr>(NakedFn))
NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
+ else if (isa<MemberExpr>(NakedFn))
+ NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc,
ExecConfig);
return S.Context.OverloadTy;
if (OrigOp->getType() == S.Context.UnknownAnyTy)
return S.Context.UnknownAnyTy;
+ if (OrigOp->getType() == S.Context.BoundMemberTy) {
+ S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
+ << OrigOp->getSourceRange();
+ return QualType();
+ }
assert(!OrigOp->getType()->isPlaceholderType());
if (ParenExpr *parenE = dyn_cast<ParenExpr>(E))
DiagnoseEqualityWithExtraParens(parenE);
- if (!E->isTypeDependent()) {
- if (E->isBoundMemberFunction(Context)) {
- Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func)
- << E->getSourceRange();
- return ExprError();
- }
+ ExprResult result = CheckPlaceholderExpr(E);
+ if (result.isInvalid()) return ExprError();
+ E = result.take();
+ if (!E->isTypeDependent()) {
if (getLangOptions().CPlusPlus)
return CheckCXXBooleanCondition(E); // C++ 6.4p4
QualType(),
diag::err_ovl_unresolvable);
+ // Bound member functions.
+ if (type == Context.BoundMemberTy) {
+ Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func)
+ << E->getSourceRange();
+ return ExprError();
+ }
+
// Expressions of unknown type.
if (type == Context.UnknownAnyTy)
return diagnoseUnknownAnyExpr(*this, E);
// second operand.
// The cv qualifiers are the union of those in the pointer and the left side,
// in accordance with 5.5p5 and 5.2.5.
- // FIXME: This returns a dereferenced member function pointer as a normal
- // function type. However, the only operation valid on such functions is
- // calling them. There's also a GCC extension to get a function pointer to the
- // thing, which is another complication, because this type - unlike the type
- // that is the result of this expression - takes the class as the first
- // argument.
- // We probably need a "MemberFunctionClosureType" or something like that.
QualType Result = MemPtr->getPointeeType();
Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers());
// operand is a pointer to a member function is a prvalue. The
// result of an ->* expression is an lvalue if its second operand
// is a pointer to data member and a prvalue otherwise.
- if (Result->isFunctionType())
+ if (Result->isFunctionType()) {
VK = VK_RValue;
- else if (isIndirect)
+ return Context.BoundMemberTy;
+ } else if (isIndirect) {
VK = VK_LValue;
- else
+ } else {
VK = lex.get()->getValueKind();
+ }
return Result;
}
return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy))
- return Diag(From->getSourceRange().getBegin(),
- diag::err_typecheck_bool_condition)
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_bool_condition)
<< From->getType() << From->getSourceRange();
return ExprError();
}
if (!TargetFunctionType->isFunctionType()) {
if (OvlExpr->hasExplicitTemplateArgs()) {
DeclAccessPair dap;
- if( FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
+ if (FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
OvlExpr, false, &dap) ) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
/// 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,
- bool Complain,
- DeclAccessPair* FoundResult) {
+FunctionDecl *
+Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
+ 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;
-
- OverloadExpr *OvlExpr = OverloadExpr::find(From).Expression;
// If we didn't actually find any template-ids, we're done.
- if (!OvlExpr->hasExplicitTemplateArgs())
+ if (!ovl->hasExplicitTemplateArgs())
return 0;
TemplateArgumentListInfo ExplicitTemplateArgs;
- OvlExpr->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
+ ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
FunctionDecl *Matched = 0;
- for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
- E = OvlExpr->decls_end(); I != E; ++I) {
+ for (UnresolvedSetIterator I = ovl->decls_begin(),
+ E = ovl->decls_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
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
+ TemplateDeductionInfo Info(Context, ovl->getNameLoc());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info)) {
continue;
}
+ assert(Specialization && "no specialization and no error?");
+
// Multiple matches; we can't resolve to a single declaration.
if (Matched) {
- if (FoundResult)
- *FoundResult = DeclAccessPair();
-
if (Complain) {
- Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
- << OvlExpr->getName();
- NoteAllOverloadCandidates(OvlExpr);
+ Diag(ovl->getExprLoc(), diag::err_addr_ovl_ambiguous)
+ << ovl->getName();
+ NoteAllOverloadCandidates(ovl);
}
return 0;
- }
+ }
- if ((Matched = Specialization) && FoundResult)
- *FoundResult = I.getPair();
+ Matched = Specialization;
+ if (FoundResult) *FoundResult = I.getPair();
}
return Matched;
// template specialization
// Last three arguments should only be supplied if Complain = true
ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
- Expr *SrcExpr, bool DoFunctionPointerConverion, bool Complain,
+ Expr *SrcExpr, bool doFunctionPointerConverion, bool complain,
const SourceRange& OpRangeForComplaining,
QualType DestTypeForComplaining,
- unsigned DiagIDForComplaining ) {
+ unsigned DiagIDForComplaining) {
+ assert(SrcExpr->getType() == Context.OverloadTy);
- assert(SrcExpr->getType() == Context.OverloadTy);
+ OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr);
- DeclAccessPair Found;
- ExprResult SingleFunctionExpression;
- if (FunctionDecl* Fn = ResolveSingleFunctionTemplateSpecialization(
- SrcExpr, false, // false -> Complain
- &Found)) {
- if (!DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) {
- // mark the expression as resolved to Fn
- SingleFunctionExpression = Owned(FixOverloadedFunctionReference(SrcExpr,
- Found, Fn));
- if (DoFunctionPointerConverion)
- SingleFunctionExpression =
- DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.take());
- }
- }
- if (!SingleFunctionExpression.isUsable()) {
- if (Complain) {
- OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
- Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
- << oe->getName() << DestTypeForComplaining << OpRangeForComplaining
- << oe->getQualifierLoc().getSourceRange();
- NoteAllOverloadCandidates(SrcExpr);
- }
+ DeclAccessPair found;
+ ExprResult SingleFunctionExpression;
+ if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization(
+ ovl.Expression, /*complain*/ false, &found)) {
+ if (DiagnoseUseOfDecl(fn, SrcExpr->getSourceRange().getBegin()))
+ return ExprError();
+
+ // It is only correct to resolve to an instance method if we're
+ // resolving a form that's permitted to be a pointer to member.
+ // Otherwise we'll end up making a bound member expression, which
+ // is illegal in all the contexts we resolve like this.
+ if (!ovl.HasFormOfMemberPointer &&
+ isa<CXXMethodDecl>(fn) &&
+ cast<CXXMethodDecl>(fn)->isInstance()) {
+ if (complain) {
+ Diag(ovl.Expression->getExprLoc(),
+ diag::err_invalid_use_of_bound_member_func)
+ << ovl.Expression->getSourceRange();
+ // TODO: I believe we only end up here if there's a mix of
+ // static and non-static candidates (otherwise the expression
+ // would have 'bound member' type, not 'overload' type).
+ // Ideally we would note which candidate was chosen and why
+ // the static candidates were rejected.
+ }
+
return ExprError();
}
- return SingleFunctionExpression;
+ // Fix the expresion to refer to 'fn'.
+ SingleFunctionExpression =
+ Owned(FixOverloadedFunctionReference(SrcExpr, found, fn));
+
+ // If desired, do function-to-pointer decay.
+ if (doFunctionPointerConverion)
+ SingleFunctionExpression =
+ DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.take());
+ }
+
+ if (!SingleFunctionExpression.isUsable()) {
+ if (complain) {
+ Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
+ << ovl.Expression->getName()
+ << DestTypeForComplaining
+ << OpRangeForComplaining
+ << ovl.Expression->getQualifierLoc().getSourceRange();
+ NoteAllOverloadCandidates(SrcExpr);
+ }
+ return ExprError();
+ }
+
+ return SingleFunctionExpression;
}
/// \brief Add a single candidate to the overload set.
/// function (and includes the object parameter), Args/NumArgs are the
/// arguments to the function call (not including the object
/// parameter). The caller needs to validate that the member
-/// expression refers to a member function or an overloaded member
-/// function.
+/// expression refers to a non-static member function or an overloaded
+/// member function.
ExprResult
Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation RParenLoc) {
+ assert(MemExprE->getType() == Context.BoundMemberTy ||
+ MemExprE->getType() == Context.OverloadTy);
+
// Dig out the member expression. This holds both the object
// argument and the member function we're referring to.
Expr *NakedMemExpr = MemExprE->IgnoreParens();
+ // Determine whether this is a call to a pointer-to-member function.
+ if (BinaryOperator *op = dyn_cast<BinaryOperator>(NakedMemExpr)) {
+ assert(op->getType() == Context.BoundMemberTy);
+ assert(op->getOpcode() == BO_PtrMemD || op->getOpcode() == BO_PtrMemI);
+
+ QualType fnType =
+ op->getRHS()->getType()->castAs<MemberPointerType>()->getPointeeType();
+
+ const FunctionProtoType *proto = fnType->castAs<FunctionProtoType>();
+ QualType resultType = proto->getCallResultType(Context);
+ ExprValueKind valueKind = Expr::getValueKindForType(proto->getResultType());
+
+ // Check that the object type isn't more qualified than the
+ // member function we're calling.
+ Qualifiers funcQuals = Qualifiers::fromCVRMask(proto->getTypeQuals());
+
+ QualType objectType = op->getLHS()->getType();
+ if (op->getOpcode() == BO_PtrMemI)
+ objectType = objectType->castAs<PointerType>()->getPointeeType();
+ Qualifiers objectQuals = objectType.getQualifiers();
+
+ Qualifiers difference = objectQuals - funcQuals;
+ difference.removeObjCGCAttr();
+ difference.removeAddressSpace();
+ if (difference) {
+ std::string qualsString = difference.getAsString();
+ Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals)
+ << fnType.getUnqualifiedType()
+ << qualsString
+ << (qualsString.find(' ') == std::string::npos ? 1 : 2);
+ }
+
+ CXXMemberCallExpr *call
+ = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs,
+ resultType, valueKind, RParenLoc);
+
+ if (CheckCallReturnType(proto->getResultType(),
+ op->getRHS()->getSourceRange().getBegin(),
+ call, 0))
+ return ExprError();
+
+ if (ConvertArgumentsForCall(call, op, 0, proto, Args, NumArgs, RParenLoc))
+ return ExprError();
+
+ return MaybeBindToTemporary(call);
+ }
+
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public);
if (!E)
return;
- if (E->isBoundMemberFunction(Context)) {
- Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func)
- << E->getSourceRange();
- return;
- }
-
SourceLocation Loc;
SourceRange R1, R2;
if (!E->isUnusedResultAWarning(Loc, R1, R2, Context))
case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break;
case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
+ case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break;
case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
case PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break;
case PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break;
case PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break;
+ case PREDEF_TYPE_BOUND_MEMBER: T = Context->BoundMemberTy; break;
case PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break;
case PREDEF_TYPE_UNKNOWN_ANY: T = Context->UnknownAnyTy; break;
case PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break;
if (S::f<int>) return; // expected-error {{call to non-static member function without an object argument}}
if (&S::f<char>) return;
if (&S::f<int>) return;
- if (s.f<char>) return; // expected-error {{contextually convertible}}
- if (s.f<int>) return; // expected-error {{contextually convertible}}
- if (&s.f<char>) return; // expected-error {{contextually convertible}}
- if (&s.f<int>) return; // expected-error {{contextually convertible}}
+ if (s.f<char>) return; // expected-error {{a bound member function may only be called}}
+ if (s.f<int>) return; // expected-error {{a bound member function may only be called}}
+ if (&s.f<char>) return; // expected-error {{cannot create a non-constant pointer to member function}}
+ if (&s.f<int>) return; // expected-error {{cannot create a non-constant pointer to member function}}
if (S::g<char>) return;
if (S::g<int>) return;
if (&s.g<int>) return;
if (S::h<42>) return;
- if (S::h<int>) return; // expected-error {{contextually convertible}}
+ if (S::h<int>) return; // expected-error {{a bound member function may only be called}}
if (&S::h<42>) return;
if (&S::h<int>) return;
if (s.h<42>) return;
- if (s.h<int>) return; // expected-error {{contextually convertible}}
+ if (s.h<int>) return; // expected-error {{a bound member function may only be called}}
if (&s.h<42>) return;
- if (&s.h<int>) return; // expected-error {{contextually convertible}}
+ if (&s.h<int>) return; // expected-error {{a bound member function may only be called}}
{ bool b = S::f<char>; } // expected-error {{call to non-static member function without an object argument}}
{ bool b = S::f<int>; } // expected-error {{call to non-static member function without an object argument}}
{ bool b = &S::f<char>; }
{ bool b = &S::f<int>; }
- { bool b = s.f<char>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
- { bool b = s.f<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
- { bool b = &s.f<char>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
- { bool b = &s.f<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ // These next two errors are terrible.
+ { bool b = s.f<char>; } // expected-error {{cannot initialize}}
+ { bool b = s.f<int>; } // expected-error {{cannot initialize}}
+ { bool b = &s.f<char>; } // expected-error {{cannot create a non-constant pointer to member function}}
+ { bool b = &s.f<int>; } // expected-error {{cannot create a non-constant pointer to member function}}
{ bool b = S::g<char>; }
{ bool b = S::g<int>; }
struct C {
C &getC() {
- return makeAC; // expected-error{{address of overloaded function 'makeAC'}}
+ // FIXME: this error message is terrible
+ return makeAC; // expected-error{{cannot bind to a value of unrelated type}}
}
- C &makeAC(); //expected-note{{candidate function}}
- const C &makeAC() const; //expected-note{{candidate function}}
+ C &makeAC();
+ const C &makeAC() const;
static void f(); // expected-note{{candidate function}}
static void f(int); // expected-note{{candidate function}}
static int& NestedFuncTemplate() { return variable; } // expected-note{{candidate function}}
template <class T>
- int& NestedMemfunTemplate() { return variable; } // expected-note{{candidate function}}
+ int& NestedMemfunTemplate() { return variable; }
int operator*() const;
template <class T>
- int operator+(T) const; // expected-note{{candidate function}}
+ int operator+(T) const;
int NonstaticMemberFunction();
static int StaticMemberFunction();
// expected-error{{cannot resolve overloaded function 'NestedFuncTemplate' from context}}
__is_lvalue_expr(::Class::NestedMemfunTemplate); // qualified-id: template \
- // expected-error{{cannot resolve overloaded function 'NestedMemfunTemplate' from context}}
+ // expected-error{{a bound member function may only be called}}
__is_lvalue_expr(::Class::operator+); // operator-function-id: template \
- // expected-error{{cannot resolve overloaded function 'operator+' from context}}
+ // expected-error{{a bound member function may only be called}}
- ASSERT_RVALUE(::Class::operator*); // operator-function-id: member function
+ //ASSERT_RVALUE(::Class::operator*); // operator-function-id: member function
}
void expr_prim_7()
ASSERT_LVALUE(StaticMemberFunction); // identifier: function
ASSERT_LVALUE(variable); // identifier: variable
ASSERT_LVALUE(dataMember); // identifier: data member
- ASSERT_RVALUE(NonstaticMemberFunction); // identifier: member function
+ //ASSERT_RVALUE(NonstaticMemberFunction); // identifier: member function
// (cont'd)...A nested-name-specifier that names a class,
// optionally followed by the keyword template (14.2), and then
// member function or a data member.
ASSERT_LVALUE(Class::dataMember);
ASSERT_LVALUE(Class::StaticMemberFunction);
- ASSERT_RVALUE(Class::NonstaticMemberFunction); // identifier: member function
+ //ASSERT_RVALUE(Class::NonstaticMemberFunction); // identifier: member function
ASSERT_LVALUE(Class::baseDataMember);
ASSERT_LVALUE(Class::BaseStaticMemberFunction);
- ASSERT_RVALUE(Class::BaseNonstaticMemberFunction); // identifier: member function
+ //ASSERT_RVALUE(Class::BaseNonstaticMemberFunction); // identifier: member function
}
};
// — Otherwise, if E1.E2 refers to a non-static member function,
// then E1.E2 is not an lvalue.
- ASSERT_RVALUE(Class().NonstaticMemberFunction);
+ //ASSERT_RVALUE(Class().NonstaticMemberFunction);
// — If E2 is a member enumerator, and the type of E2 is T, the
// expression E1.E2 is not an lvalue. The type of E1.E2 is T.
// is a pointer to data member... (cont'd)
typedef Class MakeRValue;
ASSERT_RVALUE(MakeRValue().*(&Class::dataMember));
- ASSERT_RVALUE(MakeRValue().*(&Class::NonstaticMemberFunction));
+ //ASSERT_RVALUE(MakeRValue().*(&Class::NonstaticMemberFunction));
Class lvalue;
ASSERT_LVALUE(lvalue.*(&Class::dataMember));
- ASSERT_RVALUE(lvalue.*(&Class::NonstaticMemberFunction));
+ //ASSERT_RVALUE(lvalue.*(&Class::NonstaticMemberFunction));
// (cont'd)...The result of an ->* expression is an lvalue only
// if its second operand is a pointer to data member. If the
// second operand is the null pointer to member value (4.11), the
// behavior is undefined.
ASSERT_LVALUE((&lvalue)->*(&Class::dataMember));
- ASSERT_RVALUE((&lvalue)->*(&Class::NonstaticMemberFunction));
+ //ASSERT_RVALUE((&lvalue)->*(&Class::NonstaticMemberFunction));
}
void expr_cond(bool cond)
namespace rdar9136502 {
struct X {
- int i(); // expected-note {{candidate function}}
- int i(int); // expected-note {{candidate function}}
+ int i();
+ int i(int);
};
struct Y {
- Y &operator<<(int); // expected-note{{candidate function not viable: no overload of 'i' matching 'int' for 1st argument}}
+ Y &operator<<(int); // expected-note{{candidate function not viable: no known conversion from '<bound member function type>' to 'int'}}
};
void f(X x, Y y) {
- y << x.i; // expected-error{{cannot resolve overloaded function 'i' from context}}
+ y << x.i; // expected-error{{a bound member function may only be called}}
}
}
(void)(void*)(p->*m); // expected-error {{a bound member function may only be called}}
(void)reinterpret_cast<void*>(p->*m); // expected-error {{a bound member function may only be called}}
if (p->*m) {} // expected-error {{a bound member function may only be called}}
- if (!p->*m) {} // FIXME: xpected-error {{a bound member function may only be called}} \
- // expected-error{{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'bool'}}
+ if (!(p->*m)) {} // expected-error {{a bound member function may only be called}}
if (p->m) {}; // expected-error {{a bound member function may only be called}}
- if (!p->m) {}; // FIXME: xpected-error {{a bound member function may only be called}}
+ if (!p->m) {}; // expected-error {{a bound member function may only be called}}
}
case BuiltinType::LongDouble:
case BuiltinType::NullPtr:
case BuiltinType::Overload:
+ case BuiltinType::BoundMember:
case BuiltinType::Dependent:
case BuiltinType::UnknownAny:
break;
case BuiltinType::NullPtr:
c = 'n'; break;
case BuiltinType::Overload:
+ case BuiltinType::BoundMember:
case BuiltinType::Dependent:
case BuiltinType::UnknownAny:
IgnoreResults = true;