Skip to content

Commit 27d5049

Browse files
authored
[clang][dataflow] Fix getResultObjectLocation() on CXXDefaultArgExpr. (llvm#85072)
This patch includes a test that causes an assertion failure without the other changes in this patch.
1 parent 2469208 commit 27d5049

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@ static bool isOriginalRecordConstructor(const Expr &RecordPRValue) {
771771
return !Init->isSemanticForm() || !Init->isTransparent();
772772
return isa<CXXConstructExpr>(RecordPRValue) || isa<CallExpr>(RecordPRValue) ||
773773
isa<LambdaExpr>(RecordPRValue) ||
774+
isa<CXXDefaultArgExpr>(RecordPRValue) ||
774775
isa<CXXDefaultInitExpr>(RecordPRValue) ||
775776
// The framework currently does not propagate the objects created in
776777
// the two branches of a `ConditionalOperator` because there is no way

clang/lib/Analysis/FlowSensitive/Transfer.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,25 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
450450
Env.setStorageLocation(*S, *MemberLoc);
451451
}
452452

453+
void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) {
454+
const Expr *ArgExpr = S->getExpr();
455+
assert(ArgExpr != nullptr);
456+
propagateValueOrStorageLocation(*ArgExpr, *S, Env);
457+
458+
// If this is a prvalue of record type, we consider it to be an "original
459+
// record constructor", which we always require to have a `RecordValue`.
460+
// So make sure we have a value if we didn't propagate one above.
461+
if (S->isPRValue() && S->getType()->isRecordType()) {
462+
if (Env.getValue(*S) == nullptr) {
463+
Value *Val = Env.createValue(S->getType());
464+
// We're guaranteed to always be able to create a value for record
465+
// types.
466+
assert(Val != nullptr);
467+
Env.setValue(*S, *Val);
468+
}
469+
}
470+
}
471+
453472
void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
454473
const Expr *InitExpr = S->getExpr();
455474
assert(InitExpr != nullptr);

clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -2924,6 +2924,36 @@ TEST(TransferTest, ResultObjectLocation) {
29242924
});
29252925
}
29262926

2927+
TEST(TransferTest, ResultObjectLocationForDefaultArgExpr) {
2928+
std::string Code = R"(
2929+
struct S {};
2930+
void funcWithDefaultArg(S s = S());
2931+
void target() {
2932+
funcWithDefaultArg();
2933+
// [[p]]
2934+
}
2935+
)";
2936+
2937+
using ast_matchers::cxxDefaultArgExpr;
2938+
using ast_matchers::match;
2939+
using ast_matchers::selectFirst;
2940+
runDataflow(
2941+
Code,
2942+
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2943+
ASTContext &ASTCtx) {
2944+
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2945+
2946+
auto *DefaultArg = selectFirst<CXXDefaultArgExpr>(
2947+
"default_arg",
2948+
match(cxxDefaultArgExpr().bind("default_arg"), ASTCtx));
2949+
ASSERT_NE(DefaultArg, nullptr);
2950+
2951+
// The values for default arguments aren't modeled; we merely verify
2952+
// that we can get a result object location for a default arg.
2953+
Env.getResultObjectLocation(*DefaultArg);
2954+
});
2955+
}
2956+
29272957
TEST(TransferTest, ResultObjectLocationForDefaultInitExpr) {
29282958
std::string Code = R"(
29292959
struct S {};

0 commit comments

Comments
 (0)