Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -2562,6 +2562,28 @@ +
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
+ using NS::y;
+ y(x); // Found by both unqualified lookup and ADL, doesn't match
+ }
+Matches casts that has a given cast kind.
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 preargs, ArrayRef 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 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 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(SubExprs[FN]); }
void setCallee(Expr *F) { SubExprs[FN] = F; }
+ ADLCallKind getADLCallKind() const {
+ return static_cast(CallExprBits.UsesADL);
+ }
+ void setADLCallKind(ADLCallKind V = UsesADL) {
+ CallExprBits.UsesADL = static_cast(V);
+ }
+ bool usesADL() const { return getADLCallKind() == UsesADL; }
+
Decl *getCalleeDecl();
const Decl *getCalleeDecl() const {
return const_cast(this)->getCalleeDecl();
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 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 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 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 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 Args,
+ UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef 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/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/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -1257,6 +1257,28 @@
/// \endcode
extern const internal::VariadicDynCastAllOfMatcher 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
+/// using NS::y;
+/// y(x); // Found by both unqualified lookup and ADL, doesn't match
+// }
+/// \endcode
+AST_MATCHER(CallExpr, usesADL) { return Node.usesADL(); }
+
/// Matches lambda expressions.
///
/// Example matches [&](){return 5;}
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/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2749,13 +2749,15 @@
typedef llvm::SmallSetVector AssociatedNamespaceSet;
typedef llvm::SmallSetVector AssociatedClassSet;
- void AddOverloadCandidate(FunctionDecl *Function,
- DeclAccessPair FoundDecl,
+ using ADLCallKind = CallExpr::ADLCallKind;
+
+ void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl,
ArrayRef 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 Args,
@@ -2789,13 +2791,12 @@
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool PartialOverloading = false);
- void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
- DeclAccessPair FoundDecl,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- ArrayRef Args,
- OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false,
- bool PartialOverloading = false);
+ void AddTemplateOverloadCandidate(
+ FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args,
+ OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
+ bool PartialOverloading = false,
+ ADLCallKind IsADLCandidate = ADLCallKind::NotADL);
bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
ArrayRef ParamTypes,
ArrayRef Args,
@@ -4387,12 +4388,11 @@
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig = nullptr,
bool IsExecConfig = false);
- ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
- SourceLocation LParenLoc,
- ArrayRef Arg,
- SourceLocation RParenLoc,
- Expr *Config = nullptr,
- bool IsExecConfig = false);
+ ExprResult
+ BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc,
+ ArrayRef Arg, SourceLocation RParenLoc,
+ Expr *Config = nullptr, bool IsExecConfig = false,
+ ADLCallKind UsesADL = ADLCallKind::NotADL);
ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
MultiExprArg ExecConfig,
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: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -7383,12 +7383,13 @@
if (const auto *OCE = dyn_cast(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/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -1223,11 +1223,13 @@
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
ArrayRef preargs, ArrayRef 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(UsesADL);
+
NumArgs = std::max(args.size(), MinNumArgs);
unsigned NumPreArgs = preargs.size();
CallExprBits.NumPreArgs = NumPreArgs;
@@ -1249,15 +1251,16 @@
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
ArrayRef args, QualType t, ExprValueKind VK,
- SourceLocation rparenloc, unsigned MinNumArgs)
+ SourceLocation rparenloc, unsigned MinNumArgs,
+ ADLCallKind UsesADL)
: CallExpr(C, SC, fn, ArrayRef(), args, t, VK, rparenloc,
- MinNumArgs) {}
+ MinNumArgs, UsesADL) {}
CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef args,
QualType t, ExprValueKind VK, SourceLocation rparenloc,
- unsigned MinNumArgs)
- : CallExpr(C, CallExprClass, fn, ArrayRef(), args, t, VK,
- rparenloc, MinNumArgs) {}
+ unsigned MinNumArgs, ADLCallKind UsesADL)
+ : CallExpr(C, CallExprClass, fn, ArrayRef(), args, t, VK, rparenloc,
+ MinNumArgs, UsesADL) {}
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
unsigned NumArgs, EmptyShell Empty)
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/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 Args,
- SourceLocation RParenLoc,
- Expr *Config, bool IsExecConfig) {
+ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
+ SourceLocation LParenLoc,
+ ArrayRef Args,
+ SourceLocation RParenLoc, Expr *Config,
+ bool IsExecConfig, ADLCallKind UsesADL) {
FunctionDecl *FDecl = dyn_cast_or_null(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(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/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 Args,
- OverloadCandidateSet &CandidateSet,
- bool SuppressUserConversions,
- bool PartialOverloading,
- bool AllowExplicit,
- ConversionSequenceList EarlyConversions) {
+void Sema::AddOverloadCandidate(FunctionDecl *Function,
+ DeclAccessPair FoundDecl, ArrayRef Args,
+ OverloadCandidateSet &CandidateSet,
+ bool SuppressUserConversions,
+ bool PartialOverloading, bool AllowExplicit,
+ ADLCallKind IsADLCandidate,
+ ConversionSequenceList EarlyConversions) {
const FunctionProtoType *Proto
= dyn_cast(Function->getType()->getAs());
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 Args,
- OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions,
- bool PartialOverloading) {
+void Sema::AddTemplateOverloadCandidate(
+ FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef 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(*I)) {
if (ExplicitTemplateArgs)
continue;
AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
- /*SupressUserConversions=*/false,
- PartialOverloading);
+ /*SupressUserConversions=*/false, PartialOverloading,
+ /*AllowExplicit=*/false, ADLCallKind::UsesADL);
} else {
- AddTemplateOverloadCandidate(
- cast(*I), FoundDecl, ExplicitTemplateArgs, Args,
- CandidateSet, /*SupressUserConversions=*/false, PartialOverloading);
+ AddTemplateOverloadCandidate(cast(*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/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(Record.readInt()));
}
void ASTStmtReader::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
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(E->getADLCallKind()));
Code = serialization::EXPR_CALL;
}
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{{[^ ]*}} 'Ts...' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...'
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} '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{{[^ ]*}} ]+}}> 'void' adl{{$}}
+ f(x);
+ // CHECK: CallExpr 0x{{[^ ]*}} ]+}}> 'void' adl{{$}}
+ y(x);
+}
+
+// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}NonADLCall 'void ()'
+void NonADLCall() {
+ NS::X x;
+ // CHECK: CallExpr 0x{{[^ ]*}} ]+}}> 'void'{{$}}
+ NS::f(x);
+}
+
+// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}NonADLCall2 'void ()'
+void NonADLCall2() {
+ NS::X x;
+ using NS::f;
+ // CHECK: CallExpr 0x{{[^ ]*}} ]+}}> 'void'{{$}}
+ f(x);
+ // CHECK: CallExpr 0x{{[^ ]*}} ]+}}> '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{{[^ ]*}} ]+}}> 'void'{{$}}
+ f(x);
+}
+} // namespace test_adl_call_three
\ No newline at end of file
Index: test/Import/call-expr/Inputs/F.cpp
===================================================================
--- test/Import/call-expr/Inputs/F.cpp
+++ 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/Import/call-expr/test.cpp
===================================================================
--- test/Import/call-expr/test.cpp
+++ 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: 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, too?