EricWF updated this revision to Diff 177752. EricWF marked 3 inline comments as done. EricWF added a comment.
Address review comments. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55534/new/ https://reviews.llvm.org/D55534 Files: docs/LibASTMatchersReference.html include/clang/AST/Expr.h include/clang/AST/ExprCXX.h include/clang/AST/Stmt.h include/clang/ASTMatchers/ASTMatchers.h include/clang/Sema/Overload.h include/clang/Sema/Sema.h lib/AST/ASTDumper.cpp lib/AST/ASTImporter.cpp lib/AST/Expr.cpp lib/ASTMatchers/Dynamic/Registry.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/AST/ast-dump-expr.cpp test/Import/call-expr/Inputs/F.cpp test/Import/call-expr/test.cpp unittests/ASTMatchers/ASTMatchersNodeTest.cpp
Index: unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -199,6 +199,40 @@ "-fno-delayed-template-parsing")); } +TEST(Matcher, ADLCall) { + StatementMatcher ADLMatch = callExpr(usesADL()); + StatementMatcher ADLMatchOper = cxxOperatorCallExpr(usesADL()); + auto NS_Str = R"cpp( + namespace NS { + struct X {}; + void f(X); + void operator+(X, X); + } + struct MyX {}; + void f(...); + void operator+(MyX, MyX); +)cpp"; + + auto MkStr = [&](std::string Body) -> std::string { + std::string S = NS_Str; + S += "void test_fn() { " + Body + " }"; + return S; + }; + + EXPECT_TRUE(matches(MkStr("NS::X x; f(x);"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("NS::X x; NS::f(x);"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("MyX x; f(x);"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("NS::X x; using NS::f; f(x);"), ADLMatch)); + + // Operator call expressions + EXPECT_TRUE(matches(MkStr("NS::X x; x + x;"), ADLMatch)); + EXPECT_TRUE(matches(MkStr("NS::X x; x + x;"), ADLMatchOper)); + EXPECT_TRUE(notMatches(MkStr("MyX x; x + x;"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("MyX x; x + x;"), ADLMatchOper)); + EXPECT_TRUE(matches(MkStr("NS::X x; operator+(x, x);"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("NS::X x; NS::operator+(x, x);"), ADLMatch)); +} + TEST(Matcher, Call) { // FIXME: Do we want to overload Call() to directly take // Matcher<Decl>, too? Index: test/Import/call-expr/test.cpp =================================================================== --- /dev/null +++ test/Import/call-expr/test.cpp @@ -0,0 +1,8 @@ +// RUN: clang-import-test -dump-ast -import %S/Inputs/F.cpp -expression %s | FileCheck %s +void expr() { + f(); +} + +// CHECK: FunctionDecl 0x{{[^ ]*}} <{{[^>]*}}> line:{{.*}}:{{[^ ]*}} used f 'void ()' +// CHECK: -CallExpr 0x{{[^ ]*}} <{{[^>]*}}> 'void' adl +// CHECK: -CXXOperatorCallExpr 0x{{[^ ]*}} <{{[^>]*}}> 'void' adl Index: test/Import/call-expr/Inputs/F.cpp =================================================================== --- /dev/null +++ test/Import/call-expr/Inputs/F.cpp @@ -0,0 +1,10 @@ +namespace NS { +struct X {}; +void f(X) {} +void operator+(X, X) {} +} // namespace NS +void f() { + NS::X x; + f(x); + x + x; +} Index: test/AST/ast-dump-expr.cpp =================================================================== --- test/AST/ast-dump-expr.cpp +++ test/AST/ast-dump-expr.cpp @@ -508,3 +508,46 @@ // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts...' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:14> 'int' lvalue Var 0x{{[^ ]*}} 'b' 'int' } + + +namespace NS { +struct X {}; +void f(X); +void y(...); +} // namespace NS + +// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}ADLCall 'void ()' +void ADLCall() { + NS::X x; + // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void' adl{{$}} + f(x); + // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void' adl{{$}} + y(x); +} + +// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}NonADLCall 'void ()' +void NonADLCall() { + NS::X x; + // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void'{{$}} + NS::f(x); +} + +// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}NonADLCall2 'void ()' +void NonADLCall2() { + NS::X x; + using NS::f; + // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void'{{$}} + f(x); + // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void' adl{{$}} + y(x); +} + +namespace test_adl_call_three { +using namespace NS; +// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}NonADLCall3 'void ()' +void NonADLCall3() { + X x; + // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void'{{$}} + f(x); +} +} // namespace test_adl_call_three \ No newline at end of file Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -651,6 +651,7 @@ for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); Arg != ArgEnd; ++Arg) Record.AddStmt(*Arg); + Record.push_back(static_cast<unsigned>(E->getADLCallKind())); Code = serialization::EXPR_CALL; } Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -737,6 +737,7 @@ E->setCallee(Record.readSubExpr()); for (unsigned I = 0; I != NumArgs; ++I) E->setArg(I, Record.readSubExpr()); + E->setADLCallKind(static_cast<CallExpr::ADLCallKind>(Record.readInt())); } void ASTStmtReader::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -5946,15 +5946,13 @@ /// \param PartialOverloading true if we are performing "partial" overloading /// based on an incomplete set of function arguments. This feature is used by /// code completion. -void -Sema::AddOverloadCandidate(FunctionDecl *Function, - DeclAccessPair FoundDecl, - ArrayRef<Expr *> Args, - OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions, - bool PartialOverloading, - bool AllowExplicit, - ConversionSequenceList EarlyConversions) { +void Sema::AddOverloadCandidate(FunctionDecl *Function, + DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, + ADLCallKind IsADLCandidate, + ConversionSequenceList EarlyConversions) { const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -6013,6 +6011,7 @@ Candidate.Function = Function; Candidate.Viable = true; Candidate.IsSurrogate = false; + Candidate.IsADLCandidate = IsADLCandidate; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); @@ -6715,14 +6714,11 @@ /// Add a C++ function template specialization as a candidate /// in the candidate set, using template argument deduction to produce /// an appropriate function template specialization. -void -Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - DeclAccessPair FoundDecl, - TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, - bool PartialOverloading) { +void Sema::AddTemplateOverloadCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + bool PartialOverloading, ADLCallKind IsADLCandidate) { if (!CandidateSet.isNewCandidate(FunctionTemplate)) return; @@ -6751,6 +6747,7 @@ Candidate.Function = FunctionTemplate->getTemplatedDecl(); Candidate.Viable = false; Candidate.IsSurrogate = false; + Candidate.IsADLCandidate = IsADLCandidate; // Ignore the object argument if there is one, since we don't have an object // type. Candidate.IgnoreObjectArgument = @@ -6772,7 +6769,7 @@ assert(Specialization && "Missing function template specialization?"); AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, PartialOverloading, - /*AllowExplicit*/false, Conversions); + /*AllowExplicit*/ false, IsADLCandidate, Conversions); } /// Check that implicit conversion sequences can be formed for each argument @@ -8935,17 +8932,19 @@ // set. for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { DeclAccessPair FoundDecl = DeclAccessPair::make(*I, AS_none); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { if (ExplicitTemplateArgs) continue; AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet, - /*SupressUserConversions=*/false, - PartialOverloading); + /*SupressUserConversions=*/false, PartialOverloading, + /*AllowExplicit=*/false, ADLCallKind::UsesADL); } else { - AddTemplateOverloadCandidate( - cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args, - CandidateSet, /*SupressUserConversions=*/false, PartialOverloading); + AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl, + ExplicitTemplateArgs, Args, CandidateSet, + /*SupressUserConversions=*/false, + PartialOverloading, ADLCallKind::UsesADL); } } } @@ -12023,7 +12022,8 @@ return ExprError(); Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc, - ExecConfig); + ExecConfig, /*IsExecConfig=*/false, + (*Best)->IsADLCandidate); } case OR_No_Viable_Function: { @@ -12075,7 +12075,8 @@ FunctionDecl *FDecl = (*Best)->Function; Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc, - ExecConfig); + ExecConfig, /*IsExecConfig=*/false, + (*Best)->IsADLCandidate); } } @@ -12264,9 +12265,9 @@ ResultTy = ResultTy.getNonLValueExprType(Context); Args[0] = Input; - CallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(), ArgsArray, - ResultTy, VK, OpLoc, FPOptions()); + CallExpr *TheCall = new (Context) + CXXOperatorCallExpr(Context, Op, FnExpr.get(), ArgsArray, ResultTy, + VK, OpLoc, FPOptions(), Best->IsADLCandidate); if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) return ExprError(); @@ -12496,10 +12497,9 @@ ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(), - Args, ResultTy, VK, OpLoc, - FPFeatures); + CXXOperatorCallExpr *TheCall = new (Context) + CXXOperatorCallExpr(Context, Op, FnExpr.get(), Args, ResultTy, VK, + OpLoc, FPFeatures, Best->IsADLCandidate); if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -5585,12 +5585,11 @@ /// block-pointer type. /// /// \param NDecl the declaration being called, if available -ExprResult -Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, - SourceLocation LParenLoc, - ArrayRef<Expr *> Args, - SourceLocation RParenLoc, - Expr *Config, bool IsExecConfig) { +ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, + SourceLocation LParenLoc, + ArrayRef<Expr *> Args, + SourceLocation RParenLoc, Expr *Config, + bool IsExecConfig, ADLCallKind UsesADL) { FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0); @@ -5670,13 +5669,16 @@ unsigned NumParams = Proto ? Proto->getNumParams() : 0; CallExpr *TheCall; - if (Config) + if (Config) { + assert(UsesADL == ADLCallKind::NotADL && + "CUDAKernelCallExpr should not use ADL"); TheCall = new (Context) CUDAKernelCallExpr(Context, Fn, cast<CallExpr>(Config), Args, ResultTy, VK_RValue, RParenLoc, NumParams); - else - TheCall = new (Context) - CallExpr(Context, Fn, Args, ResultTy, VK_RValue, RParenLoc, NumParams); + } else { + TheCall = new (Context) CallExpr(Context, Fn, Args, ResultTy, VK_RValue, + RParenLoc, NumParams, UsesADL); + } if (!getLangOpts().CPlusPlus) { // C cannot always handle TypoExpr nodes in builtin calls and direct Index: lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -493,6 +493,7 @@ REGISTER_MATCHER(unresolvedUsingTypenameDecl); REGISTER_MATCHER(unresolvedUsingValueDecl); REGISTER_MATCHER(userDefinedLiteral); + REGISTER_MATCHER(usesADL); REGISTER_MATCHER(usingDecl); REGISTER_MATCHER(usingDirectiveDecl); REGISTER_MATCHER(valueDecl); Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -1223,11 +1223,13 @@ CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t, ExprValueKind VK, SourceLocation rparenloc, - unsigned MinNumArgs) + unsigned MinNumArgs, ADLCallKind UsesADL) : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), fn->isInstantiationDependent(), fn->containsUnexpandedParameterPack()), RParenLoc(rparenloc) { + CallExprBits.UsesADL = static_cast<bool>(UsesADL); + NumArgs = std::max<unsigned>(args.size(), MinNumArgs); unsigned NumPreArgs = preargs.size(); CallExprBits.NumPreArgs = NumPreArgs; @@ -1249,15 +1251,16 @@ CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> args, QualType t, ExprValueKind VK, - SourceLocation rparenloc, unsigned MinNumArgs) + SourceLocation rparenloc, unsigned MinNumArgs, + ADLCallKind UsesADL) : CallExpr(C, SC, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc, - MinNumArgs) {} + MinNumArgs, UsesADL) {} CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t, ExprValueKind VK, SourceLocation rparenloc, - unsigned MinNumArgs) - : CallExpr(C, CallExprClass, fn, ArrayRef<Expr *>(), args, t, VK, - rparenloc, MinNumArgs) {} + unsigned MinNumArgs, ADLCallKind UsesADL) + : CallExpr(C, CallExprClass, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc, + MinNumArgs, UsesADL) {} CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, EmptyShell Empty) Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -7380,12 +7380,13 @@ if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) { return new (Importer.getToContext()) CXXOperatorCallExpr( Importer.getToContext(), OCE->getOperator(), ToCallee, ToArgs, ToType, - OCE->getValueKind(), ToRParenLoc, OCE->getFPFeatures()); + OCE->getValueKind(), ToRParenLoc, OCE->getFPFeatures(), + OCE->getADLCallKind()); } return new (Importer.getToContext()) CallExpr( Importer.getToContext(), ToCallee, ToArgs, ToType, E->getValueKind(), - ToRParenLoc); + ToRParenLoc, /*MinNumArgs=*/0, E->getADLCallKind()); } ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) { Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -382,6 +382,7 @@ void VisitOMPExecutableDirective(const OMPExecutableDirective *Node); // Exprs + void VisitCallExpr(const CallExpr *Node); void VisitCastExpr(const CastExpr *Node); void VisitImplicitCastExpr(const ImplicitCastExpr *Node); void VisitDeclRefExpr(const DeclRefExpr *Node); @@ -1876,6 +1877,11 @@ OS << ')'; } +void ASTDumper::VisitCallExpr(const CallExpr *Node) { + if (Node->usesADL()) + OS << " adl"; +} + void ASTDumper::VisitCastExpr(const CastExpr *Node) { OS << " <"; { Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2749,13 +2749,15 @@ typedef llvm::SmallSetVector<DeclContext *, 16> AssociatedNamespaceSet; typedef llvm::SmallSetVector<CXXRecordDecl *, 16> AssociatedClassSet; - void AddOverloadCandidate(FunctionDecl *Function, - DeclAccessPair FoundDecl, + using ADLCallKind = CallExpr::ADLCallKind; + + void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = false, + ADLCallKind IsADLCandidate = ADLCallKind::NotADL, ConversionSequenceList EarlyConversions = None); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, ArrayRef<Expr *> Args, @@ -2789,13 +2791,12 @@ OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false); - void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - DeclAccessPair FoundDecl, - TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, - bool PartialOverloading = false); + void AddTemplateOverloadCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, + bool PartialOverloading = false, + ADLCallKind IsADLCandidate = ADLCallKind::NotADL); bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes, ArrayRef<Expr *> Args, @@ -4387,12 +4388,11 @@ MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr, bool IsExecConfig = false); - ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, - SourceLocation LParenLoc, - ArrayRef<Expr *> Arg, - SourceLocation RParenLoc, - Expr *Config = nullptr, - bool IsExecConfig = false); + ExprResult + BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, + ArrayRef<Expr *> Arg, SourceLocation RParenLoc, + Expr *Config = nullptr, bool IsExecConfig = false, + ADLCallKind UsesADL = ADLCallKind::NotADL); ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, Index: include/clang/Sema/Overload.h =================================================================== --- include/clang/Sema/Overload.h +++ include/clang/Sema/Overload.h @@ -755,12 +755,12 @@ ConversionFixItGenerator Fix; /// Viable - True to indicate that this overload candidate is viable. - bool Viable; + bool Viable : 1; /// IsSurrogate - True to indicate that this candidate is a /// surrogate for a conversion to a function pointer or reference /// (C++ [over.call.object]). - bool IsSurrogate; + bool IsSurrogate : 1; /// IgnoreObjectArgument - True to indicate that the first /// argument's conversion, which for this function represents the @@ -769,7 +769,10 @@ /// implicit object argument is just a placeholder) or a /// non-static member function when the call doesn't have an /// object argument. - bool IgnoreObjectArgument; + bool IgnoreObjectArgument : 1; + + /// True if the candidate was found using ADL. + CallExpr::ADLCallKind IsADLCandidate : 1; /// FailureKind - The reason why this candidate is not viable. /// Actually an OverloadFailureKind. @@ -823,6 +826,10 @@ return Function->getNumParams(); return ExplicitCallArguments; } + + private: + friend class OverloadCandidateSet; + OverloadCandidate() : IsADLCandidate(CallExpr::NotADL) {} }; /// OverloadCandidateSet - A set of overload candidates, used in C++ Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -1257,6 +1257,26 @@ /// \endcode extern const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr; +/// Matches call expressions which were resolved using ADL. +/// +/// Example matches y(x) but not y(42) or NS::y(x). +/// \code +/// namespace NS { +/// struct X {}; +/// void y(X); +/// } +/// +/// void y(...); +/// +/// void test() { +/// NS::X x; +/// y(x); // Matches +/// NS::y(x); // Doesn't match +/// y(42); // Doesn't match +/// } +/// \endcode +AST_MATCHER(CallExpr, usesADL) { return Node.usesADL(); } + /// Matches lambda expressions. /// /// Example matches [&](){return 5;} Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -430,6 +430,9 @@ unsigned : NumExprBits; unsigned NumPreArgs : 1; + + /// True if the callee of the call expression was found using ADL. + unsigned UsesADL : 1; }; class MemberExprBitfields { Index: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -90,10 +90,12 @@ friend class ASTStmtReader; friend class ASTStmtWriter; - CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, - ArrayRef<Expr*> args, QualType t, ExprValueKind VK, - SourceLocation operatorloc, FPOptions FPFeatures) - : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc), + CXXOperatorCallExpr(ASTContext &C, OverloadedOperatorKind Op, Expr *fn, + ArrayRef<Expr *> args, QualType t, ExprValueKind VK, + SourceLocation operatorloc, FPOptions FPFeatures, + ADLCallKind UsesADL = NotADL) + : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc, + /*MinNumArgs=*/0, UsesADL), Operator(Op), FPFeatures(FPFeatures) { Range = getSourceRangeImpl(); } @@ -168,7 +170,8 @@ CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t, ExprValueKind VK, SourceLocation RP, unsigned MinNumArgs = 0) - : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP, MinNumArgs) {} + : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP, MinNumArgs, + NotADL) {} CXXMemberCallExpr(ASTContext &C, unsigned NumArgs, EmptyShell Empty) : CallExpr(C, CXXMemberCallExprClass, /*NumPreArgs=*/0, NumArgs, Empty) {} @@ -212,7 +215,7 @@ ArrayRef<Expr *> args, QualType t, ExprValueKind VK, SourceLocation RP, unsigned MinNumArgs = 0) : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP, - MinNumArgs) {} + MinNumArgs, NotADL) {} CUDAKernelCallExpr(ASTContext &C, unsigned NumArgs, EmptyShell Empty) : CallExpr(C, CUDAKernelCallExprClass, /*NumPreArgs=*/END_PREARG, NumArgs, @@ -487,16 +490,17 @@ friend class ASTStmtReader; friend class ASTStmtWriter; - UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args, + UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr *> Args, QualType T, ExprValueKind VK, SourceLocation LitEndLoc, SourceLocation SuffixLoc) - : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc), + : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc, + /*MinNumArgs=*/0, NotADL), UDSuffixLoc(SuffixLoc) {} explicit UserDefinedLiteral(const ASTContext &C, unsigned NumArgs, EmptyShell Empty) - : CallExpr(C, UserDefinedLiteralClass, /*NumPreArgs=*/0, NumArgs, - Empty) {} + : CallExpr(C, UserDefinedLiteralClass, /*NumPreArgs=*/0, NumArgs, Empty) { + } /// The kind of literal operator which is invoked. enum LiteralOperatorKind { Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -2412,14 +2412,20 @@ void updateDependenciesFromArg(Expr *Arg); +public: + enum class ADLCallKind : bool { NotADL, UsesADL }; + static constexpr ADLCallKind NotADL = ADLCallKind::NotADL; + static constexpr ADLCallKind UsesADL = ADLCallKind::UsesADL; + protected: // These versions of the constructor are for derived classes. CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t, - ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0); + ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0, + ADLCallKind UsesADL = NotADL); CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> args, QualType t, ExprValueKind VK, SourceLocation rparenloc, - unsigned MinNumArgs = 0); + unsigned MinNumArgs = 0, ADLCallKind UsesADL = NotADL); CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, EmptyShell Empty); @@ -2443,7 +2449,8 @@ /// arguments. The actual number of arguments will be the greater of /// args.size() and MinNumArgs. CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t, - ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0); + ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0, + ADLCallKind UsesADL = NotADL); /// Build an empty call expression. CallExpr(const ASTContext &C, unsigned NumArgs, EmptyShell Empty); @@ -2452,6 +2459,14 @@ Expr *getCallee() { return cast<Expr>(SubExprs[FN]); } void setCallee(Expr *F) { SubExprs[FN] = F; } + ADLCallKind getADLCallKind() const { + return static_cast<ADLCallKind>(CallExprBits.UsesADL); + } + void setADLCallKind(ADLCallKind V = UsesADL) { + CallExprBits.UsesADL = static_cast<bool>(V); + } + bool usesADL() const { return getADLCallKind() == UsesADL; } + Decl *getCalleeDecl(); const Decl *getCalleeDecl() const { return const_cast<CallExpr*>(this)->getCalleeDecl(); Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -2562,6 +2562,26 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('usesADL0')"><a name="usesADL0Anchor">usesADL</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="usesADL0"><pre>Matches call expressions which were resolved using ADL. + +Example matches y(x) but not y(42) or NS::y(x). + namespace NS { + struct X {}; + void y(X); + } + + void y(...); + + void test() { + NS::X x; + y(x); // Matches + NS::y(x); // Doesn't match + y(42); // Doesn't match + } +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>></td><td class="name" onclick="toggle('hasCastKind0')"><a name="hasCastKind0Anchor">hasCastKind</a></td><td>CastKind Kind</td></tr> <tr><td colspan="4" class="doc" id="hasCastKind0"><pre>Matches casts that has a given cast kind.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits