clang 22.0.0git
RecordOps.cpp
Go to the documentation of this file.
1//===-- RecordOps.cpp -------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Operations on records (structs, classes, and unions).
10//
11//===----------------------------------------------------------------------===//
12
14#include "clang/AST/Decl.h"
15#include "clang/AST/DeclCXX.h"
16#include "clang/AST/Type.h"
18#include "clang/Basic/LLVM.h"
19#include "llvm/ADT/StringMap.h"
20
21#define DEBUG_TYPE "dataflow"
22
23namespace clang::dataflow {
24
25static void copyField(const ValueDecl &Field, StorageLocation *SrcFieldLoc,
26 StorageLocation *DstFieldLoc, RecordStorageLocation &Dst,
27 Environment &Env) {
28 assert(Field.getType()->isReferenceType() ||
29 (SrcFieldLoc != nullptr && DstFieldLoc != nullptr));
30
31 if (Field.getType()->isRecordType()) {
33 cast<RecordStorageLocation>(*DstFieldLoc), Env);
34 } else if (Field.getType()->isReferenceType()) {
35 Dst.setChild(Field, SrcFieldLoc);
36 } else {
37 if (Value *Val = Env.getValue(*SrcFieldLoc))
38 Env.setValue(*DstFieldLoc, *Val);
39 else
40 Env.clearValue(*DstFieldLoc);
41 }
42}
43
44static void copySyntheticField(QualType FieldType, StorageLocation &SrcFieldLoc,
45 StorageLocation &DstFieldLoc, Environment &Env) {
46 if (FieldType->isRecordType()) {
48 cast<RecordStorageLocation>(DstFieldLoc), Env);
49 } else {
50 if (Value *Val = Env.getValue(SrcFieldLoc))
51 Env.setValue(DstFieldLoc, *Val);
52 else
53 Env.clearValue(DstFieldLoc);
54 }
55}
56
58 Environment &Env, const QualType TypeToCopy) {
59 auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType();
60 auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType();
61
62 auto SrcDecl = SrcType->getAsCXXRecordDecl();
63 auto DstDecl = DstType->getAsCXXRecordDecl();
64
65 const CXXRecordDecl *DeclToCopy =
66 TypeToCopy.isNull() ? nullptr : TypeToCopy->getAsCXXRecordDecl();
67
68 [[maybe_unused]] bool CompatibleTypes =
69 SrcType == DstType ||
70 (SrcDecl != nullptr && DstDecl != nullptr &&
71 (SrcDecl->isDerivedFrom(DstDecl) || DstDecl->isDerivedFrom(SrcDecl) ||
72 (DeclToCopy != nullptr && SrcDecl->isDerivedFrom(DeclToCopy) &&
73 DstDecl->isDerivedFrom(DeclToCopy))));
74
75 LLVM_DEBUG({
76 if (!CompatibleTypes) {
77 llvm::dbgs() << "Source type " << Src.getType() << "\n";
78 llvm::dbgs() << "Destination type " << Dst.getType() << "\n";
79 }
80 });
81 assert(CompatibleTypes);
82
83 if (SrcType == DstType || (SrcDecl != nullptr && DstDecl != nullptr &&
84 SrcDecl->isDerivedFrom(DstDecl))) {
85 // Dst may have children modeled from other derived types than SrcType, e.g.
86 // after casts of Dst to other types derived from DstType. Only copy the
87 // children and synthetic fields present in both Dst and SrcType.
88 const FieldSet FieldsInSrcType =
90 for (auto [Field, DstFieldLoc] : Dst.children())
91 if (const auto *FieldAsFieldDecl = dyn_cast<FieldDecl>(Field);
92 FieldAsFieldDecl && FieldsInSrcType.contains(FieldAsFieldDecl))
93 copyField(*Field, Src.getChild(*Field), DstFieldLoc, Dst, Env);
94 const llvm::StringMap<QualType> SyntheticFieldsForSrcType =
96 for (const auto &[Name, DstFieldLoc] : Dst.synthetic_fields())
97 if (SyntheticFieldsForSrcType.contains(Name))
98 copySyntheticField(DstFieldLoc->getType(), Src.getSyntheticField(Name),
99 *DstFieldLoc, Env);
100 } else if (SrcDecl != nullptr && DstDecl != nullptr &&
101 DstDecl->isDerivedFrom(SrcDecl)) {
102 // Src may have children modeled from other derived types than DstType, e.g.
103 // after other casts of Src to those types (likely in different branches,
104 // but without flow-condition-dependent field modeling). Only copy the
105 // children and synthetic fields of Src that are present in DstType.
106 const FieldSet FieldsInDstType =
108 for (auto [Field, SrcFieldLoc] : Src.children()) {
109 if (const auto *FieldAsFieldDecl = dyn_cast<FieldDecl>(Field);
110 FieldAsFieldDecl && FieldsInDstType.contains(FieldAsFieldDecl))
111 copyField(*Field, SrcFieldLoc, Dst.getChild(*Field), Dst, Env);
112 }
113 const llvm::StringMap<QualType> SyntheticFieldsForDstType =
115 for (const auto &[Name, SrcFieldLoc] : Src.synthetic_fields()) {
116 if (SyntheticFieldsForDstType.contains(Name))
117 copySyntheticField(SrcFieldLoc->getType(), *SrcFieldLoc,
118 Dst.getSyntheticField(Name), Env);
119 }
120 } else {
121 for (const FieldDecl *Field :
123 copyField(*Field, Src.getChild(*Field), Dst.getChild(*Field), Dst, Env);
124 }
125 for (const auto &[SyntheticFieldName, SyntheticFieldType] :
127 copySyntheticField(SyntheticFieldType,
128 Src.getSyntheticField(SyntheticFieldName),
129 Dst.getSyntheticField(SyntheticFieldName), Env);
130 }
131 }
132}
133
134bool recordsEqual(const RecordStorageLocation &Loc1, const Environment &Env1,
135 const RecordStorageLocation &Loc2, const Environment &Env2) {
136 LLVM_DEBUG({
139 llvm::dbgs() << "Loc1 type " << Loc1.getType() << "\n";
140 llvm::dbgs() << "Loc2 type " << Loc2.getType() << "\n";
141 }
142 });
143 assert(Loc2.getType().getCanonicalType().getUnqualifiedType() ==
145
146 for (auto [Field, FieldLoc1] : Loc1.children()) {
147 StorageLocation *FieldLoc2 = Loc2.getChild(*Field);
148
149 assert(Field->getType()->isReferenceType() ||
150 (FieldLoc1 != nullptr && FieldLoc2 != nullptr));
151
152 if (Field->getType()->isRecordType()) {
153 if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1,
154 cast<RecordStorageLocation>(*FieldLoc2), Env2))
155 return false;
156 } else if (Field->getType()->isReferenceType()) {
157 if (FieldLoc1 != FieldLoc2)
158 return false;
159 } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) {
160 return false;
161 }
162 }
163
164 for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) {
165 if (SynthFieldLoc1->getType()->isRecordType()) {
166 if (!recordsEqual(
167 *cast<RecordStorageLocation>(SynthFieldLoc1), Env1,
169 return false;
170 } else if (Env1.getValue(*SynthFieldLoc1) !=
171 Env2.getValue(Loc2.getSyntheticField(Name))) {
172 return false;
173 }
174 }
175
176 return true;
177}
178
179} // namespace clang::dataflow
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
C Language Family Type Representation.
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
Represents a member of a struct/union/class.
Definition Decl.h:3160
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
QualType getCanonicalType() const
Definition TypeBase.h:8346
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8388
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isRecordType() const
Definition TypeBase.h:8658
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
llvm::StringMap< QualType > getSyntheticFields(QualType Type)
Returns the names and types of the synthetic fields for the given record type.
FieldSet getModeledFields(QualType Type)
Returns the fields of Type, limited to the set of fields modeled by this context.
Holds the state of the program (store and heap) at a given program point.
void clearValue(const StorageLocation &Loc)
Clears any association between Loc and a value in the environment.
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
DataflowAnalysisContext & getDataflowAnalysisContext() const
Returns the DataflowAnalysisContext used by the environment.
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
A storage location for a record (struct, class, or union).
llvm::iterator_range< SyntheticFieldMap::const_iterator > synthetic_fields() const
StorageLocation * getChild(const ValueDecl &D) const
Returns the child storage location for D.
void setChild(const ValueDecl &D, StorageLocation *Loc)
Changes the child storage location for a field D of reference type.
StorageLocation & getSyntheticField(llvm::StringRef Name) const
Returns the storage location for the synthetic field Name.
llvm::iterator_range< FieldToLoc::const_iterator > children() const
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
Definition Value.h:33
Dataflow Directional Tag Classes.
Definition AdornedCFG.h:29
void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, Environment &Env, QualType TypeToCopy=QualType())
Copies a record (struct, class, or union) from Src to Dst.
Definition RecordOps.cpp:57
bool recordsEqual(const RecordStorageLocation &Loc1, const Environment &Env1, const RecordStorageLocation &Loc2, const Environment &Env2)
Returns whether the records Loc1 and Loc2 are equal.
static void copyField(const ValueDecl &Field, StorageLocation *SrcFieldLoc, StorageLocation *DstFieldLoc, RecordStorageLocation &Dst, Environment &Env)
Definition RecordOps.cpp:25
static void copySyntheticField(QualType FieldType, StorageLocation &SrcFieldLoc, StorageLocation &DstFieldLoc, Environment &Env)
Definition RecordOps.cpp:44
llvm::SmallSetVector< const FieldDecl *, 4 > FieldSet
A set of FieldDecl *.
Definition ASTOps.h:43
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
U cast(CodeGen::Address addr)
Definition Address.h:327