Index: include/clang/Analysis/ConstructionContext.h =================================================================== --- include/clang/Analysis/ConstructionContext.h +++ include/clang/Analysis/ConstructionContext.h @@ -597,9 +597,14 @@ }; class ArgumentConstructionContext : public ConstructionContext { - const Expr *CE; // The call of which the context is an argument. - unsigned Index; // Which argument we're constructing. - const CXXBindTemporaryExpr *BTE; // Whether the object needs to be destroyed. + // The call of which the context is an argument. + const Expr *CE; + // Which argument we're constructing. Note that when numbering between + // arguments and parameters is inconsistent (eg., operator calls), + // this is the index of the argument, not of the parameter. + unsigned Index; + // Whether the object needs to be destroyed. + const CXXBindTemporaryExpr *BTE; friend class ConstructionContext; // Allows to create<>() itself. Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -684,7 +684,7 @@ void findConstructionContexts(const ConstructionContextLayer *Layer, Stmt *Child); - // Scan all arguments of a call expression for a construction context. + // Scan all arguments of a call-like expression for a construction context. // These sorts of call expressions don't have a common superclass, // hence strict duck-typing. template ::value>> void findConstructionContextsForArguments(CallLikeExpr *E) { for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { + if (i == 0) { + // FIXME: This check will run for non-CallExpr variants as well, + // which is redundant. + if (const auto *OE = dyn_cast(E)) + if (dyn_cast_or_null(OE->getDirectCallee())) { + // It's an operator's this-argument that's mistaken for argument 0 + // due to an AST inconsistency. + // FIXME: Actually introduce the respective construction context. + continue; + } + } + Expr *Arg = E->getArg(i); if (Arg->getType()->getAsCXXRecordDecl() && !Arg->isGLValue()) findConstructionContexts( Index: test/Analysis/cfg-rich-constructors.cpp =================================================================== --- test/Analysis/cfg-rich-constructors.cpp +++ test/Analysis/cfg-rich-constructors.cpp @@ -960,3 +960,37 @@ C c = C(); } } // namespace copy_elision_with_extra_arguments + + +namespace operators { +class C { +public: + C(int); + C &operator+(C Other); +}; + +// FIXME: Find construction context for the this-argument of the operator. +// CHECK: void testOperators() +// CHECK: [B1] +// CHECK-NEXT: 1: operator+ +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class operators::C &(*)(class operators::C)) +// CHECK-NEXT: 3: 1 +// CXX11-NEXT: 4: [B1.3] (CXXConstructExpr, class operators::C) +// CXX11-NEXT: 5: operators::C([B1.4]) (CXXFunctionalCastExpr, ConstructorConversion, class operators::C) +// CXX11-NEXT: 6: 2 +// CXX11-ELIDE-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.9], [B1.10], class operators::C) +// CXX11-NOELIDE-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.9], class operators::C) +// CXX11-NEXT: 8: operators::C([B1.7]) (CXXFunctionalCastExpr, ConstructorConversion, class operators::C) +// CXX11-NEXT: 9: [B1.8] +// CXX11-NEXT: 10: [B1.9] (CXXConstructExpr, [B1.11]+1, class operators::C) +// CXX11-NEXT: 11: [B1.5] + [B1.10] (OperatorCall) +// CXX17-NEXT: 4: [B1.3] (CXXConstructExpr, class operators::C) +// CXX17-NEXT: 5: operators::C([B1.4]) (CXXFunctionalCastExpr, ConstructorConversion, class operators::C) +// CXX17-NEXT: 6: 2 +// CXX17-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.9]+1, class operators::C) +// CXX17-NEXT: 8: operators::C([B1.7]) (CXXFunctionalCastExpr, ConstructorConversion, class operators::C) +// CXX17-NEXT: 9: [B1.5] + [B1.8] (OperatorCall) +void testOperators() { + C(1) + C(2); +} +} // namespace operators