diff options
author | John McCall <rjmccall@apple.com> | 2011-04-26 20:42:42 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-04-26 20:42:42 +0000 |
commit | 0009fcc39e19e1576495533f06e980acc0a954fd (patch) | |
tree | 951bcaea4ed6e770a431362d0d8954be2ce5d9b2 | |
parent | 1b06c71668183c30c54704ed02a0071318295481 (diff) | |
download | bcm5719-llvm-0009fcc39e19e1576495533f06e980acc0a954fd.tar.gz bcm5719-llvm-0009fcc39e19e1576495533f06e980acc0a954fd.zip |
Make yet another placeholder type, this one marking that an expression is a bound
member function, i.e. something of the form 'x.f' where 'f' is a non-static
member function. Diagnose this in the general case. Some of the new diagnostics
are probably worse than the old ones, but we now get this right much more
universally, and there's certainly room for improvement in the diagnostics.
llvm-svn: 130239
30 files changed, 364 insertions, 229 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 820c5a288d5..959e158cebc 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -426,7 +426,7 @@ public: 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. diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 2969b752336..ed207ace0c3 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -486,6 +486,11 @@ public: /// \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, diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 9ed30563598..cfdfae1ee36 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1190,6 +1190,9 @@ public: /// 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) @@ -1488,32 +1491,52 @@ public: 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: @@ -1546,11 +1569,11 @@ 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; } @@ -4300,6 +4323,12 @@ inline bool Type::isPlaceholderType() const { 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 { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0e813a6e123..b3d4890fdaf 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -112,6 +112,7 @@ namespace clang { class ObjCPropertyDecl; class ObjCProtocolDecl; class OverloadCandidateSet; + class OverloadExpr; class ParenListExpr; class ParmVarDecl; class Preprocessor; @@ -1413,7 +1414,7 @@ public: bool Complain, DeclAccessPair &Found); - FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From, + FunctionDecl *ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, bool Complain = false, DeclAccessPair* Found = 0); diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 72252d4da80..06be2179156 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -491,8 +491,10 @@ namespace clang { 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 diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 3d74d3a9380..a31969dc907 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -402,6 +402,9 @@ void ASTContext::InitBuiltinTypes() { // 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); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 2b15904fdba..7c45543f66a 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1363,6 +1363,7 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { 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! diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index dd1a317f4a1..2a5917c4594 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -820,11 +820,11 @@ QualType CallExpr::getCallReturnType() const { 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(); } @@ -1623,6 +1623,30 @@ bool Expr::isBoundMemberFunction(ASTContext &Ctx) const { 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 diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 127431ba7d6..1a1a0a36a65 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -837,6 +837,28 @@ bool CXXDependentScopeMemberExpr::isImplicitAccess() const { 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, @@ -857,6 +879,11 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, 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 { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index b62442d6d2a..14ee74be124 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1471,6 +1471,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Overload: case BuiltinType::Dependent: + case BuiltinType::BoundMember: case BuiltinType::UnknownAny: assert(false && "Overloaded and dependent types shouldn't get to name mangling"); diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 046c33ddda6..2ba4cf2f67c 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -718,6 +718,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { 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; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 124bf133052..d43a121881e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1169,6 +1169,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const { 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"; diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index cc648304285..34e7693e307 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -234,6 +234,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::NullPtr: case BuiltinType::Overload: case BuiltinType::Dependent: + case BuiltinType::BoundMember: case BuiltinType::UnknownAny: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 228d9c6c5e6..94f95053425 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -289,10 +289,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, 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()); @@ -321,8 +321,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, // 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); } diff --git a/clang/lib/CodeGen/CGRTTI.cpp b/clang/lib/CodeGen/CGRTTI.cpp index b8d234f8a62..c73b199e31f 100644 --- a/clang/lib/CodeGen/CGRTTI.cpp +++ b/clang/lib/CodeGen/CGRTTI.cpp @@ -196,8 +196,9 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { 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: diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 255d12f2cc3..8db6fe51868 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -229,7 +229,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { #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: { @@ -283,8 +283,9 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { 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!"); diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index 648011b1f05..ed54f0f5442 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -160,10 +160,6 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, // 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); @@ -305,6 +301,11 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, /// 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; @@ -1540,12 +1541,6 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, 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". @@ -1557,6 +1552,9 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, return ExprError(); CastExpr = CastExprRes.take(); + if (CastExpr->getType() == Context.BoundMemberTy) + return CheckPlaceholderExpr(CastExpr); // will always fail + if (CastExpr->getType() == Context.OverloadTy) { ExprResult SingleFunctionExpr = ResolveAndFixSingleFunctionTemplateSpecialization( diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c90c5132506..212f584f5fe 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3934,12 +3934,20 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } 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?"); @@ -4051,6 +4059,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, << 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(); @@ -4424,6 +4434,16 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, } } 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) { @@ -4858,91 +4878,33 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, 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)) @@ -4951,6 +4913,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, 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); @@ -8282,6 +8246,11 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, 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()); @@ -10301,13 +10270,11 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { 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 @@ -10728,6 +10695,13 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { 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); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index edfa4a532df..f8ad763e4bd 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2857,13 +2857,6 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, // 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()); @@ -2900,12 +2893,14 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, // 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; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 06c097c620c..6e6bf22be0b 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -3623,8 +3623,8 @@ ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) { 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(); } @@ -7202,7 +7202,7 @@ public: 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)) { @@ -7502,32 +7502,29 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetTyp /// 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 @@ -7544,7 +7541,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, // 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)) { @@ -7553,21 +7550,20 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, 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; @@ -7581,39 +7577,65 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, // 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. @@ -8499,16 +8521,66 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, /// 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); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index e6609c08e21..5e21a367588 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -77,12 +77,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { 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)) diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index b5bbe74ce3d..782e5c6aa79 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -50,6 +50,7 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { 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; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 03d9a05f3e3..65ff731d3a8 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3638,6 +3638,7 @@ QualType ASTReader::GetType(TypeID ID) { 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; diff --git a/clang/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/clang/test/CXX/over/over.over/p2-resolve-single-template-id.cpp index b1cc1e3cfab..544a66d9e39 100644 --- a/clang/test/CXX/over/over.over/p2-resolve-single-template-id.cpp +++ b/clang/test/CXX/over/over.over/p2-resolve-single-template-id.cpp @@ -137,10 +137,10 @@ namespace member_pointers { 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; @@ -152,22 +152,23 @@ namespace member_pointers { 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>; } diff --git a/clang/test/SemaCXX/addr-of-overloaded-function.cpp b/clang/test/SemaCXX/addr-of-overloaded-function.cpp index a1079ff5bac..a36fd582db2 100644 --- a/clang/test/SemaCXX/addr-of-overloaded-function.cpp +++ b/clang/test/SemaCXX/addr-of-overloaded-function.cpp @@ -57,11 +57,12 @@ struct B 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}} diff --git a/clang/test/SemaCXX/expression-traits.cpp b/clang/test/SemaCXX/expression-traits.cpp index 6b644ea84da..4555192280f 100644 --- a/clang/test/SemaCXX/expression-traits.cpp +++ b/clang/test/SemaCXX/expression-traits.cpp @@ -189,12 +189,12 @@ struct Class : BaseClass 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(); @@ -237,12 +237,12 @@ struct Class : BaseClass // 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() @@ -256,7 +256,7 @@ struct Class : BaseClass 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 @@ -267,11 +267,11 @@ struct Class : BaseClass // 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 } }; @@ -371,7 +371,7 @@ void expr_ref_4() // — 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. @@ -502,17 +502,17 @@ void expr_mptr_oper() // 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) diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp index 8d39af10af0..44d013fe796 100644 --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -387,15 +387,15 @@ void test_lookup_through_using() { 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}} } } diff --git a/clang/test/SemaCXX/ptrtomember.cpp b/clang/test/SemaCXX/ptrtomember.cpp index 8afcb112a36..c3917333a54 100644 --- a/clang/test/SemaCXX/ptrtomember.cpp +++ b/clang/test/SemaCXX/ptrtomember.cpp @@ -27,8 +27,7 @@ void f3(S3* p, void (S3::*m)()) { (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}} } diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index a50c987b3c2..a0e204d61fe 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1412,6 +1412,7 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { case BuiltinType::LongDouble: case BuiltinType::NullPtr: case BuiltinType::Overload: + case BuiltinType::BoundMember: case BuiltinType::Dependent: case BuiltinType::UnknownAny: break; diff --git a/clang/tools/libclang/CIndexUSRs.cpp b/clang/tools/libclang/CIndexUSRs.cpp index 30173d3e7ed..68871e94951 100644 --- a/clang/tools/libclang/CIndexUSRs.cpp +++ b/clang/tools/libclang/CIndexUSRs.cpp @@ -570,6 +570,7 @@ void USRGenerator::VisitType(QualType T) { case BuiltinType::NullPtr: c = 'n'; break; case BuiltinType::Overload: + case BuiltinType::BoundMember: case BuiltinType::Dependent: case BuiltinType::UnknownAny: IgnoreResults = true; |