diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index bea15ce9bd24d..ee2581143e114 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -508,6 +508,11 @@ class ResultObjectVisitor : public RecursiveASTVisitor { isa(E)) { return; } + if (auto *Op = dyn_cast(E); + Op && Op->getOpcode() == BO_Cmp) { + // Builtin `<=>` returns a `std::strong_ordering` object. + return; + } if (auto *InitList = dyn_cast(E)) { if (!InitList->isSemanticForm()) diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 00dafb2988c69..d8bcc3da4b8b1 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -3098,6 +3098,58 @@ TEST(TransferTest, ResultObjectLocationForCXXOperatorCallExpr) { }); } +// Check that the `std::strong_ordering` object returned by builtin `<=>` has a +// correctly modeled result object location. +TEST(TransferTest, ResultObjectLocationForBuiltinSpaceshipOperator) { + std::string Code = R"( + namespace std { + // This is the minimal definition required to get + // `Sema::CheckComparisonCategoryType()` to accept this fake. + struct strong_ordering { + enum class ordering { less, equal, greater }; + ordering o; + static const strong_ordering less; + static const strong_ordering equivalent; + static const strong_ordering equal; + static const strong_ordering greater; + }; + + inline constexpr strong_ordering strong_ordering::less = + { strong_ordering::ordering::less }; + inline constexpr strong_ordering strong_ordering::equal = + { strong_ordering::ordering::equal }; + inline constexpr strong_ordering strong_ordering::equivalent = + { strong_ordering::ordering::equal }; + inline constexpr strong_ordering strong_ordering::greater = + { strong_ordering::ordering::greater }; + } + void target(int i, int j) { + auto ordering = i <=> j; + // [[p]] + } + )"; + using ast_matchers::binaryOperator; + using ast_matchers::hasOperatorName; + using ast_matchers::match; + using ast_matchers::selectFirst; + using ast_matchers::traverse; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + + auto *Spaceship = selectFirst( + "op", + match(binaryOperator(hasOperatorName("<=>")).bind("op"), ASTCtx)); + + EXPECT_EQ( + &Env.getResultObjectLocation(*Spaceship), + &getLocForDecl(ASTCtx, Env, "ordering")); + }, + LangStandard::lang_cxx20); +} + TEST(TransferTest, ResultObjectLocationForStdInitializerListExpr) { std::string Code = R"( namespace std {