@@ -3400,6 +3400,60 @@ TEST(TransferTest, ResultObjectLocationDontVisitNestedRecordDecl) {
3400
3400
ASTContext &ASTCtx) {});
3401
3401
}
3402
3402
3403
+ TEST (TransferTest, ResultObjectLocationDontVisitUnevaluatedContexts) {
3404
+ // This is a crash repro.
3405
+ // We used to crash because when propagating result objects, we would visit
3406
+ // unevaluated contexts, but we don't model fields used only in these.
3407
+
3408
+ auto testFunction = [](llvm::StringRef Code, llvm::StringRef TargetFun) {
3409
+ runDataflow (
3410
+ Code,
3411
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3412
+ ASTContext &ASTCtx) {},
3413
+ LangStandard::lang_gnucxx17,
3414
+ /* ApplyBuiltinTransfer= */ true , TargetFun);
3415
+ };
3416
+
3417
+ std::string Code = R"cc(
3418
+ // Definitions needed for `typeid`.
3419
+ namespace std {
3420
+ class type_info {};
3421
+ class bad_typeid {};
3422
+ } // namespace std
3423
+
3424
+ struct S1 {};
3425
+ struct S2 { S1 s1; };
3426
+
3427
+ // We test each type of unevaluated context from a different target
3428
+ // function. Some types of unevaluated contexts may actually cause the
3429
+ // field `s1` to be modeled, and we don't want this to "pollute" the tests
3430
+ // for the other unevaluated contexts.
3431
+ void decltypeTarget() {
3432
+ decltype(S2{}) Dummy;
3433
+ }
3434
+ void typeofTarget() {
3435
+ typeof(S2{}) Dummy;
3436
+ }
3437
+ void typeidTarget() {
3438
+ #if __has_feature(cxx_rtti)
3439
+ typeid(S2{});
3440
+ #endif
3441
+ }
3442
+ void sizeofTarget() {
3443
+ sizeof(S2{});
3444
+ }
3445
+ void noexceptTarget() {
3446
+ noexcept(S2{});
3447
+ }
3448
+ )cc" ;
3449
+
3450
+ testFunction (Code, " decltypeTarget" );
3451
+ testFunction (Code, " typeofTarget" );
3452
+ testFunction (Code, " typeidTarget" );
3453
+ testFunction (Code, " sizeofTarget" );
3454
+ testFunction (Code, " noexceptTarget" );
3455
+ }
3456
+
3403
3457
TEST (TransferTest, StaticCast) {
3404
3458
std::string Code = R"(
3405
3459
void target(int Foo) {
0 commit comments