File tree 3 files changed +50
-0
lines changed
lib/Analysis/FlowSensitive
unittests/Analysis/FlowSensitive
3 files changed +50
-0
lines changed Original file line number Diff line number Diff line change @@ -771,6 +771,7 @@ static bool isOriginalRecordConstructor(const Expr &RecordPRValue) {
771
771
return !Init->isSemanticForm () || !Init->isTransparent ();
772
772
return isa<CXXConstructExpr>(RecordPRValue) || isa<CallExpr>(RecordPRValue) ||
773
773
isa<LambdaExpr>(RecordPRValue) ||
774
+ isa<CXXDefaultArgExpr>(RecordPRValue) ||
774
775
isa<CXXDefaultInitExpr>(RecordPRValue) ||
775
776
// The framework currently does not propagate the objects created in
776
777
// the two branches of a `ConditionalOperator` because there is no way
Original file line number Diff line number Diff line change @@ -450,6 +450,25 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
450
450
Env.setStorageLocation (*S, *MemberLoc);
451
451
}
452
452
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
+
453
472
void VisitCXXDefaultInitExpr (const CXXDefaultInitExpr *S) {
454
473
const Expr *InitExpr = S->getExpr ();
455
474
assert (InitExpr != nullptr );
Original file line number Diff line number Diff line change @@ -2924,6 +2924,36 @@ TEST(TransferTest, ResultObjectLocation) {
2924
2924
});
2925
2925
}
2926
2926
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
+
2927
2957
TEST (TransferTest, ResultObjectLocationForDefaultInitExpr) {
2928
2958
std::string Code = R"(
2929
2959
struct S {};
You can’t perform that action at this time.
0 commit comments