@@ -726,27 +726,70 @@ void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
726
726
// so allow these as an exception.
727
727
assert (E.isGLValue () ||
728
728
E.getType ()->isSpecificBuiltinType (BuiltinType::BuiltinFn));
729
- setStorageLocationInternal (E, Loc);
729
+ const Expr &CanonE = ignoreCFGOmittedNodes (E);
730
+ assert (!ExprToLoc.contains (&CanonE));
731
+ ExprToLoc[&CanonE] = &Loc;
730
732
}
731
733
732
734
StorageLocation *Environment::getStorageLocation (const Expr &E) const {
733
735
// See comment in `setStorageLocation()`.
734
736
assert (E.isGLValue () ||
735
737
E.getType ()->isSpecificBuiltinType (BuiltinType::BuiltinFn));
736
- return getStorageLocationInternal (E);
738
+ auto It = ExprToLoc.find (&ignoreCFGOmittedNodes (E));
739
+ return It == ExprToLoc.end () ? nullptr : &*It->second ;
740
+ }
741
+
742
+ // Returns whether a prvalue of record type is the one that originally
743
+ // constructs the object (i.e. it doesn't propagate it from one of its
744
+ // children).
745
+ static bool isOriginalRecordConstructor (const Expr &RecordPRValue) {
746
+ if (auto *Init = dyn_cast<InitListExpr>(&RecordPRValue))
747
+ return !Init->isSemanticForm () || !Init->isTransparent ();
748
+ return isa<CXXConstructExpr>(RecordPRValue) || isa<CallExpr>(RecordPRValue) ||
749
+ isa<LambdaExpr>(RecordPRValue) ||
750
+ // The framework currently does not propagate the objects created in
751
+ // the two branches of a `ConditionalOperator` because there is no way
752
+ // to reconcile their storage locations, which are different. We
753
+ // therefore claim that the `ConditionalOperator` is the expression
754
+ // that originally constructs the object.
755
+ // Ultimately, this will be fixed by propagating locations down from
756
+ // the result object, rather than up from the original constructor as
757
+ // we do now (see also the FIXME in the documentation for
758
+ // `getResultObjectLocation()`).
759
+ isa<ConditionalOperator>(RecordPRValue);
737
760
}
738
761
739
762
RecordStorageLocation &
740
- Environment::getResultObjectLocation (const Expr &RecordPRValue) {
763
+ Environment::getResultObjectLocation (const Expr &RecordPRValue) const {
741
764
assert (RecordPRValue.getType ()->isRecordType ());
742
765
assert (RecordPRValue.isPRValue ());
743
766
744
- if (StorageLocation *ExistingLoc = getStorageLocationInternal (RecordPRValue))
745
- return *cast<RecordStorageLocation>(ExistingLoc);
746
- auto &Loc = cast<RecordStorageLocation>(
747
- DACtx->getStableStorageLocation (RecordPRValue));
748
- setStorageLocationInternal (RecordPRValue, Loc);
749
- return Loc;
767
+ // Returns a storage location that we can use if assertions fail.
768
+ auto FallbackForAssertFailure =
769
+ [this , &RecordPRValue]() -> RecordStorageLocation & {
770
+ return cast<RecordStorageLocation>(
771
+ DACtx->getStableStorageLocation (RecordPRValue));
772
+ };
773
+
774
+ if (isOriginalRecordConstructor (RecordPRValue)) {
775
+ auto *Val = cast_or_null<RecordValue>(getValue (RecordPRValue));
776
+ // The builtin transfer function should have created a `RecordValue` for all
777
+ // original record constructors.
778
+ assert (Val);
779
+ if (!Val)
780
+ return FallbackForAssertFailure ();
781
+ return Val->getLoc ();
782
+ }
783
+
784
+ // Expression nodes that propagate a record prvalue should have exactly one
785
+ // child.
786
+ llvm::SmallVector<const Stmt *> children (RecordPRValue.child_begin (),
787
+ RecordPRValue.child_end ());
788
+ assert (children.size () == 1 );
789
+ if (children.empty ())
790
+ return FallbackForAssertFailure ();
791
+
792
+ return getResultObjectLocation (*cast<Expr>(children[0 ]));
750
793
}
751
794
752
795
PointerValue &Environment::getOrCreateNullPointerValue (QualType PointeeType) {
@@ -760,6 +803,11 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
760
803
}
761
804
762
805
void Environment::setValue (const Expr &E, Value &Val) {
806
+ if (auto *RecordVal = dyn_cast<RecordValue>(&Val)) {
807
+ assert (isOriginalRecordConstructor (E) ||
808
+ &RecordVal->getLoc () == &getResultObjectLocation (E));
809
+ }
810
+
763
811
assert (E.isPRValue ());
764
812
ExprToVal[&E] = &Val;
765
813
}
@@ -799,18 +847,6 @@ Value *Environment::createValue(QualType Type) {
799
847
return Val;
800
848
}
801
849
802
- void Environment::setStorageLocationInternal (const Expr &E,
803
- StorageLocation &Loc) {
804
- const Expr &CanonE = ignoreCFGOmittedNodes (E);
805
- assert (!ExprToLoc.contains (&CanonE));
806
- ExprToLoc[&CanonE] = &Loc;
807
- }
808
-
809
- StorageLocation *Environment::getStorageLocationInternal (const Expr &E) const {
810
- auto It = ExprToLoc.find (&ignoreCFGOmittedNodes (E));
811
- return It == ExprToLoc.end () ? nullptr : &*It->second ;
812
- }
813
-
814
850
Value *Environment::createValueUnlessSelfReferential (
815
851
QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
816
852
int &CreatedValuesCount) {
@@ -1044,6 +1080,7 @@ RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) {
1044
1080
if (auto *ExistingVal = cast_or_null<RecordValue>(Env.getValue (Expr))) {
1045
1081
auto &NewVal = Env.create <RecordValue>(ExistingVal->getLoc ());
1046
1082
Env.setValue (Expr, NewVal);
1083
+ Env.setValue (NewVal.getLoc (), NewVal);
1047
1084
return NewVal;
1048
1085
}
1049
1086
0 commit comments