forked from checkedc/checkedc-clang
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathConstraintVariables.h
More file actions
674 lines (555 loc) · 29 KB
/
ConstraintVariables.h
File metadata and controls
674 lines (555 loc) · 29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
//=--ConstraintVariables.h----------------------------------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// The class allocates constraint variables and maps program locations
// (specified by PersistentSourceLocs) to constraint variables.
//
// The allocation of constraint variables is a little nuanced. For a given
// variable, there might be multiple constraint variables. For example, some
// declaration of the form:
//
// int **p = ... ;
//
// would be given two constraint variables, visualized like this:
//
// int * q_(i+1) * q_i p = ... ;
//
// The constraint variable at the "highest" or outer-most level of the type
// is the lowest numbered constraint variable for a given declaration.
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_3C_CONSTRAINTVARIABLES_H
#define LLVM_CLANG_3C_CONSTRAINTVARIABLES_H
#include "clang/3C/Constraints.h"
#include "clang/3C/OptionalParams.h"
#include "clang/3C/ProgramVar.h"
#include "clang/AST/ASTContext.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
class ProgramInfo;
// Holds integers representing constraint variables, with semantics as
// defined in the text above
typedef std::set<ConstraintKey> CVars;
// Holds Atoms, one for each of the pointer (*) declared in the program.
typedef std::vector<Atom *> CAtoms;
struct MkStringOpts {
bool EmitName = true;
bool ForItype = false;
bool EmitPointee = false;
bool UnmaskTypedef = false;
std::string UseName = "";
bool ForItypeBase = false;
};
#define MKSTRING_OPTS(...) PACK_OPTS(MkStringOpts, __VA_ARGS__)
// Base class for ConstraintVariables. A ConstraintVariable can either be a
// PointerVariableConstraint or a FunctionVariableConstraint. The difference
// is that FunctionVariableConstraints have constraints on the return value
// and on each parameter.
class ConstraintVariable {
public:
enum ConstraintVariableKind { PointerVariable, FunctionVariable };
ConstraintVariableKind getKind() const { return Kind; }
private:
ConstraintVariableKind Kind;
protected:
std::string OriginalType;
// Underlying name of the C variable this ConstraintVariable represents.
std::string Name;
// Set of constraint variables that have been constrained due to a
// bounds-safe interface (itype). They are remembered as being constrained
// so that later on we do not introduce a spurious constraint
// making those variables WILD.
std::set<ConstraintKey> ConstrainedVars;
// A flag to indicate that we already forced argConstraints to be equated
// Avoids infinite recursive calls.
bool HasEqArgumentConstraints;
// Flag to indicate if this Constraint Variable has a bounds key.
bool ValidBoundsKey;
// Bounds key of this Constraint Variable.
BoundsKey BKey;
// Is this Constraint Variable for a declaration?
bool IsForDecl;
// Only subclasses should call this
ConstraintVariable(ConstraintVariableKind K, std::string T, std::string N)
: Kind(K), OriginalType(T), Name(N), HasEqArgumentConstraints(false),
ValidBoundsKey(false), IsForDecl(false) {}
public:
// Create a "for-rewriting" representation of this ConstraintVariable.
// The 'emitName' parameter is true when the generated string should include
// the name of the variable, false for just the type.
// The 'forIType' parameter is true when the generated string is expected
// to be used inside an itype.
virtual std::string mkString(Constraints &CS,
const MkStringOpts &Opts = {}) const = 0;
// Debug printing of the constraint variable.
virtual void print(llvm::raw_ostream &O) const = 0;
virtual void dump() const = 0;
virtual void dumpJson(llvm::raw_ostream &O) const = 0;
virtual bool srcHasItype() const = 0;
virtual bool srcHasBounds() const = 0;
bool hasBoundsKey() const { return ValidBoundsKey; }
BoundsKey getBoundsKey() const {
assert(ValidBoundsKey && "No valid Bkey");
return BKey;
}
void setBoundsKey(BoundsKey NK) {
ValidBoundsKey = true;
BKey = NK;
}
virtual bool solutionEqualTo(Constraints &, const ConstraintVariable *,
bool ComparePtyp = true) const = 0;
virtual void constrainToWild(Constraints &CS,
const std::string &Rsn) const = 0;
virtual void constrainToWild(Constraints &CS, const std::string &Rsn,
PersistentSourceLoc *PL) const = 0;
// Return true if this variable was checked in the input. Checked variables
// might solve to WILD, and unchecked variables might solve to checked. Use
// isSolutionChecked if you want these final solved types.
virtual bool isOriginallyChecked() const = 0;
// Returns true if any of the constraint variables 'within' this instance
// have a binding in E other than top. E should be the EnvironmentMap that
// results from running unification on the set of constraints and the
// environment.
virtual bool isSolutionChecked(const EnvironmentMap &E) const = 0;
// Returns true if this constraint variable has a different checked type after
// running unification. Note that if the constraint variable had a checked
// type in the input program, it will have the same checked type after solving
// so, the type will not have changed. To test if the type is checked, use
// isSolutionChecked instead.
virtual bool anyChanges(const EnvironmentMap &E) const = 0;
// Return true if all atoms (pointer levels) in this variable are checked.
// This is in contrast to isSolutionChecked which will return true if any atom
// is checked.
virtual bool isSolutionFullyChecked(const EnvironmentMap &E) const = 0;
// Here, AIdx is the pointer level which needs to be checked.
// By default, we check for all pointer levels (or VarAtoms)
virtual bool hasWild(const EnvironmentMap &E, int AIdx = -1) const = 0;
virtual bool hasArr(const EnvironmentMap &E, int AIdx = -1) const = 0;
virtual bool hasNtArr(const EnvironmentMap &E, int AIdx = -1) const = 0;
// Force use of equality constraints in function calls for this CV
virtual void equateArgumentConstraints(ProgramInfo &I) = 0;
// Internally combine the constraints and other data from the first parameter
// with this constraint variable. Used with redeclarations, especially of
// functions declared in multiple files.
virtual void mergeDeclaration(ConstraintVariable *, ProgramInfo &,
std::string &ReasonFailed) = 0;
std::string getOriginalTy() const { return OriginalType; }
// Get the original type string that can be directly
// used for rewriting.
std::string getRewritableOriginalTy() const;
std::string getName() const { return Name; }
// TODO is the word `valid` doing any real work here? or can it be dropped?
void setValidDecl() { IsForDecl = true; }
bool isForValidDecl() const { return IsForDecl; }
// By default, 3C allows itypes to be re-solved arbitrarily. But in several
// cases, we need to restrict itype re-solving; this function applies those
// restrictions. (It isn't needed for fully checked types because 3C doesn't
// allow checked types to be re-solved yet.)
//
// In some cases, we don't want the checked portion of the type to change, but
// the itype can still become a fully checked type; we achieve that by copying
// ConstAtoms from SrcVars vector into the main VarAtoms vector, which forces
// the solved checked type for the variable to be the same as it was in the
// source. In other cases, we don't want the itype to change at all; to
// achieve that, we additionally constrain the internal variables to not
// change.
//
// Some cases in which the itype must not change at all are indicated by
// passing a reason for the "root cause of wildness" as ReasonUnchangeable.
// Otherwise ReasonUnchangeable should be set to the empty string.
virtual void equateWithItype(ProgramInfo &CS,
const std::string &ReasonUnchangeable,
PersistentSourceLoc *PSL) = 0;
virtual ConstraintVariable *getCopy(Constraints &CS) = 0;
virtual ~ConstraintVariable(){};
};
typedef std::set<ConstraintVariable *> CVarSet;
typedef Option<ConstraintVariable> CVarOption;
enum ConsAction { Safe_to_Wild, Wild_to_Safe, Same_to_Same };
void constrainConsVarGeq(const std::set<ConstraintVariable *> &LHS,
const std::set<ConstraintVariable *> &RHS,
Constraints &CS, PersistentSourceLoc *PL,
ConsAction CA, bool DoEqType, ProgramInfo *Info,
bool HandleBoundsKey = true);
void constrainConsVarGeq(ConstraintVariable *LHS, const CVarSet &RHS,
Constraints &CS, PersistentSourceLoc *PL,
ConsAction CA, bool DoEqType, ProgramInfo *Info,
bool HandleBoundsKey = true);
void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS,
Constraints &CS, PersistentSourceLoc *PL,
ConsAction CA, bool DoEqType, ProgramInfo *Info,
bool HandleBoundsKey = true);
// True if [C] is a PVConstraint that contains at least one Atom (i.e.,
// it represents a C pointer)
bool isAValidPVConstraint(const ConstraintVariable *C);
class PointerVariableConstraint;
class FunctionVariableConstraint;
// We need to store the level inside the type AST at which the first
// typedef occurs. This allows us to stop rewriting once we hit the
// first typedef. (All subsequent typedefs will not be rewritten, as
// rewriting will stop.)
struct InternalTypedefInfo {
bool HasTypedef;
int TypedefLevel;
std::string TypedefName;
};
// Represents an individual constraint on a pointer variable.
// This could contain a reference to a FunctionVariableConstraint
// in the case of a function pointer declaration.
class PointerVariableConstraint : public ConstraintVariable {
public:
enum Qualification {
ConstQualification,
VolatileQualification,
RestrictQualification
};
static PointerVariableConstraint *
getWildPVConstraint(Constraints &CS, const std::string &Rsn,
PersistentSourceLoc *PSL = nullptr);
static PointerVariableConstraint *getPtrPVConstraint(Constraints &CS);
static PointerVariableConstraint *getNonPtrPVConstraint(Constraints &CS);
static PointerVariableConstraint *getNamedNonPtrPVConstraint(StringRef Name,
Constraints &CS);
static PointerVariableConstraint *
addAtomPVConstraint(PointerVariableConstraint *PVC, ConstAtom *PtrTyp,
Constraints &CS);
static PointerVariableConstraint *
derefPVConstraint(PointerVariableConstraint *PVC);
private:
std::string BaseType;
CAtoms Vars;
std::vector<ConstAtom *> SrcVars;
FunctionVariableConstraint *FV;
std::map<uint32_t, std::set<Qualification>> QualMap;
enum OriginalArrType { O_Pointer, O_SizedArray, O_UnSizedArray };
// Map from pointer idx to original type and size.
// If the original variable U was:
// * A pointer, then U -> (a,b) , a = O_Pointer, b has no meaning.
// * A sized array, then U -> (a,b) , a = O_SizedArray, b is static size.
// * An unsized array, then U -(a,b) , a = O_UnSizedArray, b has no meaning.
std::map<uint32_t, std::pair<OriginalArrType, uint64_t>> ArrSizes;
// To help rewriting preserve macros and constant expressions in arrays size
// expressions, the source strings for bounds of arrays are also stored.
std::map<uint32_t, std::string> ArrSizeStrs;
// True if this variable has an itype in the original source code.
bool SrcHasItype;
// The string representation of the itype of in the original source. This
// string is empty if the variable did not have an itype OR if the itype was
// implicitly declared by a bounds declaration on an unchecked pointer.
std::string ItypeStr;
// Get the qualifier string (e.g., const, etc) for the provided
// pointer type into the provided string stream (ss).
void getQualString(uint32_t TypeIdx, std::ostringstream &Ss) const;
void insertQualType(uint32_t TypeIdx, QualType &QTy);
// This function tries to emit an array size for the variable.
// and returns true if the variable is an array and a size is emitted.
bool emitArraySize(std::stack<std::string> &ConstSizeArrs, uint32_t TypeIdx,
Atom::AtomKind Kind) const;
void addArrayAnnotations(std::stack<std::string> &ConstArrs,
std::deque<std::string> &EndStrs) const;
// Utility used by the constructor to obtain a string representation of a
// declaration's base type. To preserve macros, this we first try to take
// the type directly from source code. Where that is not possible, the type
// is regenerated from the type in the clang AST.
static std::string extractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
QualType QT, const Type *Ty,
const ASTContext &C);
// Try to extract string representation of the base type for a declaration
// from the source code. If the base type cannot be extracted from source, an
// empty string is returned instead.
static std::string tryExtractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
QualType QT, const Type *Ty,
const ASTContext &C);
// Flag to indicate that this constraint is a part of function prototype
// e.g., Parameters or Return.
bool PartOfFuncPrototype;
// For the function parameters and returns,
// this set contains the constraint variable of
// the values used as arguments.
std::set<ConstraintVariable *> ArgumentConstraints;
// Get solution for the atom of a pointer.
const ConstAtom *getSolution(const Atom *A, const EnvironmentMap &E) const;
PointerVariableConstraint(PointerVariableConstraint *Ot, Constraints &CS);
PointerVariableConstraint *Parent;
// String representing declared bounds expression.
std::string BoundsAnnotationStr;
// Does this variable represent a generic type? Which one (or -1 for none)?
// Generic types can be used with fewer restrictions, so this field is used
// stop assignments with generic variables from forcing constraint variables
// to be wild.
int GenericIndex;
// Empty array pointers are represented the same as standard pointers. This
// lets pointers be passed to functions expecting a zero width array. This
// flag is used to discriminate between standard pointer and zero width array
// pointers.
bool IsZeroWidthArray;
bool IsTypedef = false;
TypedefNameDecl *TDT;
std::string TypedefString;
// Does the type internally contain a typedef, and if so: at what level and
// what is it's name?
struct InternalTypedefInfo TypedefLevelInfo;
// Is this a pointer to void? Possibly with multiple levels of indirection.
bool IsVoidPtr;
// Constructor for when we know a CVars and a type string.
PointerVariableConstraint(CAtoms V, std::vector<ConstAtom *> SV,
std::string T, std::string Name,
FunctionVariableConstraint *F, std::string Is,
int Generic = -1)
: ConstraintVariable(PointerVariable, "" /*not used*/, Name), BaseType(T),
Vars(V), SrcVars(SV), FV(F), SrcHasItype(!Is.empty()), ItypeStr(Is),
PartOfFuncPrototype(false), Parent(nullptr), BoundsAnnotationStr(""),
GenericIndex(Generic), IsZeroWidthArray(false), IsVoidPtr(false) {}
public:
std::string getTy() const { return BaseType; }
bool getArrPresent() const;
// Check if the outermost pointer is an unsized array.
bool isTopCvarUnsizedArr() const;
// Check if any of the pointers is either a sized or unsized arr.
bool hasSomeSizedArr() const;
bool isTypedef(void);
void setTypedef(TypedefNameDecl *T, std::string S);
// Return true if this constraint had an itype in the original source code.
bool srcHasItype() const override { return SrcHasItype; }
// Return the string representation of the itype for this constraint if an
// itype was present in the original source code. Returns empty string
// otherwise.
std::string getItype() const { return ItypeStr; }
// Check if this variable has bounds annotation.
bool srcHasBounds() const override { return !BoundsAnnotationStr.empty(); }
// Get bounds annotation.
std::string getBoundsStr() const { return BoundsAnnotationStr; }
bool getIsGeneric() const { return GenericIndex >= 0; }
int getGenericIndex() const { return GenericIndex; }
// Was this variable a checked pointer in the input program?
// This is important for two reasons: (1) externs that are checked should be
// kept that way during solving, (2) nothing that was originally checked
// should be modified during rewriting.
bool isOriginallyChecked() const override {
return llvm::any_of(Vars, [](Atom *A) { return isa<ConstAtom>(A); });
}
bool isSolutionChecked(const EnvironmentMap &E) const override;
bool isSolutionFullyChecked(const EnvironmentMap &E) const override;
bool isVoidPtr() const { return IsVoidPtr; }
bool solutionEqualTo(Constraints &CS, const ConstraintVariable *CV,
bool ComparePtyp = true) const override;
// Constructors for creating PVConstraints from a specific declaration (either
// a typedef of declarator declaration). These constructors call the larger
// constructor below with type, type source info, and name instantiated with
// information in D.
PointerVariableConstraint(clang::DeclaratorDecl *D, ProgramInfo &I,
const clang::ASTContext &C);
PointerVariableConstraint(clang::TypedefDecl *D, ProgramInfo &I,
const clang::ASTContext &C);
PointerVariableConstraint(clang::Expr *E, ProgramInfo &I,
const clang::ASTContext &C);
// QT: Defines the type for the constraint variable. One atom is added for
// each level of pointer (or array) indirection in the type.
// D: If this constraint is generated because of a variable declaration, this
// should be a pointer to the the declaration AST node. May be null if the
// constraint is not generated by a declaration.
// N: Name for the constraint variable. Use for rewriting declarations that
// need an identifier. Otherwise used to give descriptive names to atoms in
// the constraint graph.
// I and C: Context objects required for this construction. It is expected
// that all constructor calls will take the same global objects here.
// inFunc: If this variable is part of a function prototype, this string is
// the name of the function. nullptr otherwise.
// ForceGenericIndex: CheckedC supports generic types (_Itype_for_any) which
// need less restrictive constraints. Set >= 0 to indicate
// that this variable should be considered generic.
// TSI: TypeSourceInfo object gives access to information about the source
// code representation of the type. Allows for more precise rewriting by
// preserving the exact syntax used to write types that aren't rewritten
// by 3C. If this is null, then the type will be reconstructed from QT.
PointerVariableConstraint(const clang::QualType &QT, clang::DeclaratorDecl *D,
std::string N, ProgramInfo &I,
const clang::ASTContext &C,
std::string *InFunc = nullptr,
int ForceGenericIndex = -1,
bool VarAtomForChecked = false,
TypeSourceInfo *TSI = nullptr,
const clang::QualType &ItypeT = QualType());
const CAtoms &getCvars() const { return Vars; }
// Include new ConstAtoms, supplemental info, and merge function pointers
void mergeDeclaration(ConstraintVariable *From, ProgramInfo &I,
std::string &ReasonFailed) override;
static bool classof(const ConstraintVariable *S) {
return S->getKind() == PointerVariable;
}
std::string gatherQualStrings(void) const;
std::string mkString(Constraints &CS,
const MkStringOpts &Opts = {}) const override;
FunctionVariableConstraint *getFV() const { return FV; }
void print(llvm::raw_ostream &O) const override;
void dump() const override { print(llvm::errs()); }
void dumpJson(llvm::raw_ostream &O) const override;
void constrainToWild(Constraints &CS, const std::string &Rsn) const override;
void constrainToWild(Constraints &CS, const std::string &Rsn,
PersistentSourceLoc *PL) const override;
void constrainOuterTo(Constraints &CS, ConstAtom *C, bool DoLB = false,
bool Soft = false);
void constrainIdxTo(Constraints &CS, ConstAtom *C, unsigned int Idx,
bool DoLB = false, bool Soft = false);
bool anyChanges(const EnvironmentMap &E) const override;
bool anyArgumentIsWild(const EnvironmentMap &E);
bool hasWild(const EnvironmentMap &E, int AIdx = -1) const override;
bool hasArr(const EnvironmentMap &E, int AIdx = -1) const override;
bool hasNtArr(const EnvironmentMap &E, int AIdx = -1) const override;
void equateArgumentConstraints(ProgramInfo &I) override;
bool isPartOfFunctionPrototype() const { return PartOfFuncPrototype; }
// Add the provided constraint variable as an argument constraint.
bool addArgumentConstraint(ConstraintVariable *DstCons, ProgramInfo &Info);
// Get the set of constraint variables corresponding to the arguments.
const std::set<ConstraintVariable *> &getArgumentConstraints() const;
PointerVariableConstraint *getCopy(Constraints &CS) override;
// Retrieve the atom at the specified index. This function includes special
// handling for generic constraint variables to create deeper pointers as
// they are needed.
Atom *getAtom(unsigned int AtomIdx, Constraints &CS);
~PointerVariableConstraint() override{};
void equateWithItype(ProgramInfo &CS, const std::string &ReasonUnchangeable,
PersistentSourceLoc *PSL) override;
};
typedef PointerVariableConstraint PVConstraint;
// Name for function return, for debugging
#define RETVAR "$ret"
// This class contains a pair of PVConstraints that represent an internal and
// external view of a variable for use as the parameter and return constraints
// of FunctionVariableConstraints. The internal constraint represents how the
// variable is used inside the function. The external constraint represents
// how it can be used by callers to the function. For example, when a variable
// is used unsafely inside the function, the internal constraint variable will
// solve to an unchecked type, but the external constraint variable will still
// be checked. The rewriting of the function then gives it an itype, allowing
// callers to use the external checked type.
class FVComponentVariable {
private:
friend class FunctionVariableConstraint;
PVConstraint *InternalConstraint;
PVConstraint *ExternalConstraint;
std::string SourceDeclaration;
void linkInternalExternal(ProgramInfo &I, bool EquateChecked) const;
public:
FVComponentVariable()
: InternalConstraint(nullptr), ExternalConstraint(nullptr),
SourceDeclaration("") {}
FVComponentVariable(FVComponentVariable *Ot, Constraints &CS);
FVComponentVariable(const clang::QualType &QT, const clang::QualType &ITypeT,
clang::DeclaratorDecl *D, std::string N, ProgramInfo &I,
const clang::ASTContext &C, std::string *InFunc,
bool HasItype);
void mergeDeclaration(FVComponentVariable *From, ProgramInfo &I,
std::string &ReasonFailed);
std::string mkItypeStr(Constraints &CS, bool ForItypeBase = false) const;
std::string mkTypeStr(Constraints &CS, bool EmitName,
std::string UseName = "",
bool ForItypeBase = false) const;
std::string mkString(Constraints &CS, bool EmitName = true,
bool ForItypeBase = false) const;
bool hasItypeSolution(Constraints &CS) const;
bool hasCheckedSolution(Constraints &CS) const;
PVConstraint *getInternal() const { return InternalConstraint; }
PVConstraint *getExternal() const { return ExternalConstraint; }
void equateWithItype(ProgramInfo &CS, const std::string &ReasonUnchangeable,
PersistentSourceLoc *PSL) const;
bool solutionEqualTo(Constraints &CS, const FVComponentVariable *CV,
bool ComparePtyp) const;
};
// Constraints on a function type. Also contains a 'name' parameter for
// when a re-write of a function pointer is needed.
class FunctionVariableConstraint : public ConstraintVariable {
private:
FunctionVariableConstraint(FunctionVariableConstraint *Ot, Constraints &CS);
// N constraints on the return value of the function.
FVComponentVariable ReturnVar;
// A vector of K sets of N constraints on the parameter values, for
// K parameters accepted by the function.
std::vector<FVComponentVariable> ParamVars;
// File name in which this declaration is found.
std::string FileName;
bool Hasproto;
bool Hasbody;
bool IsStatic;
FunctionVariableConstraint *Parent;
// Flag to indicate whether this is a function pointer or not.
bool IsFunctionPtr;
// Count of type parameters from `_Itype_for_any(...)`.
int TypeParams;
void equateFVConstraintVars(ConstraintVariable *CV, ProgramInfo &Info) const;
public:
FunctionVariableConstraint()
: ConstraintVariable(FunctionVariable, "", ""), FileName(""),
Hasproto(false), Hasbody(false), IsStatic(false), Parent(nullptr),
IsFunctionPtr(false) {}
FunctionVariableConstraint(clang::DeclaratorDecl *D, ProgramInfo &I,
const clang::ASTContext &C);
FunctionVariableConstraint(clang::TypedefDecl *D, ProgramInfo &I,
const clang::ASTContext &C);
FunctionVariableConstraint(const clang::Type *Ty, clang::DeclaratorDecl *D,
std::string N, ProgramInfo &I,
const clang::ASTContext &C,
TypeSourceInfo *TSI = nullptr);
PVConstraint *getExternalReturn() const {
return ReturnVar.ExternalConstraint;
}
PVConstraint *getInternalReturn() const {
return ReturnVar.InternalConstraint;
}
const FVComponentVariable *getCombineReturn() const { return &ReturnVar; }
size_t numParams() const { return ParamVars.size(); }
bool hasProtoType() const { return Hasproto; }
bool hasBody() const { return Hasbody; }
void setHasBody(bool Hbody) { this->Hasbody = Hbody; }
static bool classof(const ConstraintVariable *S) {
return S->getKind() == FunctionVariable;
}
// Merge return value and all params
void mergeDeclaration(ConstraintVariable *FromCV, ProgramInfo &I,
std::string &ReasonFailed) override;
PVConstraint *getExternalParam(unsigned I) const {
assert(I < ParamVars.size());
return ParamVars.at(I).ExternalConstraint;
}
PVConstraint *getInternalParam(unsigned I) const {
assert(I < ParamVars.size());
return ParamVars.at(I).InternalConstraint;
}
const FVComponentVariable *getCombineParam(unsigned I) const {
assert(I < ParamVars.size());
return &ParamVars.at(I);
}
bool srcHasItype() const override;
bool srcHasBounds() const override;
int getGenericIndex() const {
return ReturnVar.ExternalConstraint->getGenericIndex();
}
bool solutionEqualTo(Constraints &CS, const ConstraintVariable *CV,
bool ComparePtyp = true) const override;
std::string mkString(Constraints &CS,
const MkStringOpts &Opts = {}) const override;
void print(llvm::raw_ostream &O) const override;
void dump() const override { print(llvm::errs()); }
void dumpJson(llvm::raw_ostream &O) const override;
void constrainToWild(Constraints &CS, const std::string &Rsn) const override;
void constrainToWild(Constraints &CS, const std::string &Rsn,
PersistentSourceLoc *PL) const override;
bool anyChanges(const EnvironmentMap &E) const override;
bool hasWild(const EnvironmentMap &E, int AIdx = -1) const override;
bool hasArr(const EnvironmentMap &E, int AIdx = -1) const override;
bool hasNtArr(const EnvironmentMap &E, int AIdx = -1) const override;
void equateArgumentConstraints(ProgramInfo &P) override;
FunctionVariableConstraint *getCopy(Constraints &CS) override;
bool isOriginallyChecked() const override;
bool isSolutionChecked(const EnvironmentMap &E) const override;
bool isSolutionFullyChecked(const EnvironmentMap &E) const override;
void equateWithItype(ProgramInfo &CS, const std::string &ReasonUnchangeable,
PersistentSourceLoc *PSL) override;
~FunctionVariableConstraint() override {}
};
typedef FunctionVariableConstraint FVConstraint;
#endif // LLVM_CLANG_3C_CONSTRAINTVARIABLES_H