30
30
#include " llvm/ADT/MapVector.h"
31
31
#include " llvm/Support/Compiler.h"
32
32
#include " llvm/Support/ErrorHandling.h"
33
+ #include < memory>
33
34
#include < type_traits>
34
35
#include < utility>
35
36
@@ -344,17 +345,6 @@ class Environment {
344
345
// / location of the result object to pass in `this`, even though prvalues are
345
346
// / otherwise not associated with storage locations.
346
347
// /
347
- // / FIXME: Currently, this simply returns a stable storage location for `E`,
348
- // / but this doesn't do the right thing in scenarios like the following:
349
- // / ```
350
- // / MyClass c = some_condition()? MyClass(foo) : MyClass(bar);
351
- // / ```
352
- // / Here, `MyClass(foo)` and `MyClass(bar)` will have two different storage
353
- // / locations, when in fact their storage locations should be the same.
354
- // / Eventually, we want to propagate storage locations from result objects
355
- // / down to the prvalues that initialize them, similar to the way that this is
356
- // / done in Clang's CodeGen.
357
- // /
358
348
// / Requirements:
359
349
// / `E` must be a prvalue of record type.
360
350
RecordStorageLocation &
@@ -462,7 +452,13 @@ class Environment {
462
452
// / Initializes the fields (including synthetic fields) of `Loc` with values,
463
453
// / unless values of the field type are not supported or we hit one of the
464
454
// / limits at which we stop producing values.
465
- void initializeFieldsWithValues (RecordStorageLocation &Loc);
455
+ // / If `Type` is provided, initializes only those fields that are modeled for
456
+ // / `Type`; this is intended for use in cases where `Loc` is a derived type
457
+ // / and we only want to initialize the fields of a base type.
458
+ void initializeFieldsWithValues (RecordStorageLocation &Loc, QualType Type);
459
+ void initializeFieldsWithValues (RecordStorageLocation &Loc) {
460
+ initializeFieldsWithValues (Loc, Loc.getType ());
461
+ }
466
462
467
463
// / Assigns `Val` as the value of `Loc` in the environment.
468
464
void setValue (const StorageLocation &Loc, Value &Val);
@@ -653,6 +649,9 @@ class Environment {
653
649
LLVM_DUMP_METHOD void dump (raw_ostream &OS) const ;
654
650
655
651
private:
652
+ using PrValueToResultObject =
653
+ llvm::DenseMap<const Expr *, RecordStorageLocation *>;
654
+
656
655
// The copy-constructor is for use in fork() only.
657
656
Environment (const Environment &) = default ;
658
657
@@ -682,8 +681,10 @@ class Environment {
682
681
// / Initializes the fields (including synthetic fields) of `Loc` with values,
683
682
// / unless values of the field type are not supported or we hit one of the
684
683
// / limits at which we stop producing values (controlled by `Visited`,
685
- // / `Depth`, and `CreatedValuesCount`).
686
- void initializeFieldsWithValues (RecordStorageLocation &Loc,
684
+ // / `Depth`, and `CreatedValuesCount`). If `Type` is different from
685
+ // / `Loc.getType()`, initializes only those fields that are modeled for
686
+ // / `Type`.
687
+ void initializeFieldsWithValues (RecordStorageLocation &Loc, QualType Type,
687
688
llvm::DenseSet<QualType> &Visited, int Depth,
688
689
int &CreatedValuesCount);
689
690
@@ -702,22 +703,45 @@ class Environment {
702
703
// / and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
703
704
void initFieldsGlobalsAndFuncs (const FunctionDecl *FuncDecl);
704
705
706
+ static PrValueToResultObject
707
+ buildResultObjectMap (DataflowAnalysisContext *DACtx,
708
+ const FunctionDecl *FuncDecl,
709
+ RecordStorageLocation *ThisPointeeLoc,
710
+ RecordStorageLocation *LocForRecordReturnVal);
711
+
705
712
// `DACtx` is not null and not owned by this object.
706
713
DataflowAnalysisContext *DACtx;
707
714
708
- // FIXME: move the fields `CallStack`, `ReturnVal `, `ReturnLoc` and
709
- // `ThisPointeeLoc` into a separate call-context object, shared between
710
- // environments in the same call.
715
+ // FIXME: move the fields `CallStack`, `ResultObjectMap `, `ReturnVal`,
716
+ // `ReturnLoc` and ` ThisPointeeLoc` into a separate call-context object,
717
+ // shared between environments in the same call.
711
718
// https://github.com/llvm/llvm-project/issues/59005
712
719
713
720
// `DeclContext` of the block being analysed if provided.
714
721
std::vector<const DeclContext *> CallStack;
715
722
716
- // Value returned by the function (if it has non-reference return type).
723
+ // Maps from prvalues of record type to their result objects. Shared between
724
+ // all environments for the same function.
725
+ // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
726
+ // here, though the cost is acceptable: The overhead of a `shared_ptr` is
727
+ // incurred when it is copied, and this happens only relatively rarely (when
728
+ // we fork the environment). The need for a `shared_ptr` will go away once we
729
+ // introduce a shared call-context object (see above).
730
+ std::shared_ptr<PrValueToResultObject> ResultObjectMap;
731
+
732
+ // The following three member variables handle various different types of
733
+ // return values.
734
+ // - If the return type is not a reference and not a record: Value returned
735
+ // by the function.
717
736
Value *ReturnVal = nullptr ;
718
- // Storage location of the reference returned by the function (if it has
719
- // reference return type) .
737
+ // - If the return type is a reference: Storage location of the reference
738
+ // returned by the function .
720
739
StorageLocation *ReturnLoc = nullptr ;
740
+ // - If the return type is a record or the function being analyzed is a
741
+ // constructor: Storage location into which the return value should be
742
+ // constructed.
743
+ RecordStorageLocation *LocForRecordReturnVal = nullptr ;
744
+
721
745
// The storage location of the `this` pointee. Should only be null if the
722
746
// function being analyzed is only a function and not a method.
723
747
RecordStorageLocation *ThisPointeeLoc = nullptr ;
0 commit comments