Skip to content

Commit 5d364ab

Browse files
authored
Initial enhancement to allow 3C to infer generics (checkedc#683)
Enhancement for functions with single `void*` parameter or return to be converted into `_For_any` generics.
1 parent eefab62 commit 5d364ab

21 files changed

+605
-146
lines changed

clang/include/clang/3C/ConstraintResolver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class ConstraintResolver {
4242

4343
CVarSet getCalleeConstraintVars(CallExpr *CE);
4444

45+
bool isCastofGeneric(CastExpr *C);
46+
4547
// Handle assignment of RHS expression to LHS expression using the
4648
// given action.
4749
void constrainLocalAssign(Stmt *TSt, Expr *LHS, Expr *RHS,

clang/include/clang/3C/ConstraintVariables.h

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,9 @@ class PointerVariableConstraint : public ConstraintVariable {
354354
// Generic types can be used with fewer restrictions, so this field is used
355355
// stop assignments with generic variables from forcing constraint variables
356356
// to be wild.
357-
int GenericIndex;
357+
// Source is generated from the source code, Inferred is set internally
358+
int SourceGenericIndex;
359+
int InferredGenericIndex;
358360

359361
// Empty array pointers are represented the same as standard pointers. This
360362
// lets pointers be passed to functions expecting a zero width array. This
@@ -378,7 +380,8 @@ class PointerVariableConstraint : public ConstraintVariable {
378380
PointerVariableConstraint(std::string Name) :
379381
ConstraintVariable(PointerVariable, "", Name), FV(nullptr),
380382
SrcHasItype(false), PartOfFuncPrototype(false), Parent(nullptr),
381-
GenericIndex(-1), IsZeroWidthArray(false), IsTypedef(false), TDT(nullptr),
383+
SourceGenericIndex(-1), InferredGenericIndex(-1),
384+
IsZeroWidthArray(false), IsTypedef(false), TDT(nullptr),
382385
TypedefLevelInfo({}), IsVoidPtr(false) {}
383386

384387
public:
@@ -404,9 +407,12 @@ class PointerVariableConstraint : public ConstraintVariable {
404407
// Get bounds annotation.
405408
std::string getBoundsStr() const { return BoundsAnnotationStr; }
406409

407-
bool getIsGeneric() const { return GenericIndex >= 0; }
408-
int getGenericIndex() const { return GenericIndex; }
409-
410+
bool isGeneric() const { return InferredGenericIndex >= 0; }
411+
int getGenericIndex() const { return InferredGenericIndex; }
412+
void setGenericIndex(int idx) { InferredGenericIndex = idx; }
413+
bool isGenericChanged() const {
414+
return SourceGenericIndex != InferredGenericIndex;
415+
}
410416
// Was this variable a checked pointer in the input program?
411417
// This is important for two reasons: (1) externs that are checked should be
412418
// kept that way during solving, (2) nothing that was originally checked
@@ -449,6 +455,10 @@ class PointerVariableConstraint : public ConstraintVariable {
449455
// ForceGenericIndex: CheckedC supports generic types (_Itype_for_any) which
450456
// need less restrictive constraints. Set >= 0 to indicate
451457
// that this variable should be considered generic.
458+
// PotentialGeneric: Whether this may become generic after analysis. Disables
459+
// constraint to wild for non-generics. If you use this
460+
// you'll have to add that constraint later if it is
461+
// not generic.
452462
// TSI: TypeSourceInfo object gives access to information about the source
453463
// code representation of the type. Allows for more precise rewriting by
454464
// preserving the exact syntax used to write types that aren't rewritten
@@ -458,6 +468,7 @@ class PointerVariableConstraint : public ConstraintVariable {
458468
const clang::ASTContext &C,
459469
std::string *InFunc = nullptr,
460470
int ForceGenericIndex = -1,
471+
bool PotentialGeneric = false,
461472
bool VarAtomForChecked = false,
462473
TypeSourceInfo *TSI = nullptr,
463474
const clang::QualType &ItypeT = QualType());
@@ -550,7 +561,7 @@ class FVComponentVariable {
550561
FVComponentVariable(const clang::QualType &QT, const clang::QualType &ITypeT,
551562
clang::DeclaratorDecl *D, std::string N, ProgramInfo &I,
552563
const clang::ASTContext &C, std::string *InFunc,
553-
bool HasItype);
564+
bool PotentialGeneric, bool HasItype);
554565

555566
void mergeDeclaration(FVComponentVariable *From, ProgramInfo &I,
556567
std::string &ReasonFailed);
@@ -567,6 +578,11 @@ class FVComponentVariable {
567578
PVConstraint *getInternal() const { return InternalConstraint; }
568579
PVConstraint *getExternal() const { return ExternalConstraint; }
569580

581+
void setGenericIndex(int idx) {
582+
ExternalConstraint->setGenericIndex(idx);
583+
InternalConstraint->setGenericIndex(idx);
584+
}
585+
570586
void equateWithItype(ProgramInfo &CS, const std::string &ReasonUnchangeable,
571587
PersistentSourceLoc *PSL) const;
572588

@@ -595,7 +611,7 @@ class FunctionVariableConstraint : public ConstraintVariable {
595611
// Flag to indicate whether this is a function pointer or not.
596612
bool IsFunctionPtr;
597613

598-
// Count of type parameters from `_Itype_for_any(...)`.
614+
// Count of type parameters (originally from `_Itype_for_any(...)`).
599615
int TypeParams;
600616

601617
void equateFVConstraintVars(ConstraintVariable *CV, ProgramInfo &Info) const;
@@ -652,9 +668,24 @@ class FunctionVariableConstraint : public ConstraintVariable {
652668
bool srcHasItype() const override;
653669
bool srcHasBounds() const override;
654670

671+
// The number of type variables
672+
int getGenericParams() const {
673+
return TypeParams;
674+
}
675+
// remove added generics
676+
// use when we constrain a potential generic param to wild
677+
void resetGenericParams() {
678+
TypeParams = 0;
679+
}
680+
681+
// The type parameter index of the return
655682
int getGenericIndex() const {
656683
return ReturnVar.ExternalConstraint->getGenericIndex();
657684
}
685+
// Change the type parameter index of the return
686+
void setGenericIndex(int idx) {
687+
ReturnVar.ExternalConstraint->setGenericIndex(idx);
688+
}
658689

659690
bool solutionEqualTo(Constraints &CS, const ConstraintVariable *CV,
660691
bool ComparePtyp = true) const override;

clang/include/clang/3C/Constraints.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class ConstraintsGraph;
3232

3333
#define DEFAULT_REASON "UNKNOWN_REASON"
3434
#define POINTER_IS_ARRAY_REASON "Pointer is array but alltypes is disabled."
35+
#define VOID_TYPE_REASON "Default void* type"
3536
#define UNWRITABLE_REASON "Source code in non-writable file."
3637

3738
template <typename T> struct PComp {

clang/include/clang/3C/DeclRewriter.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,10 @@ class FunctionDeclBuilder : public RecursiveASTVisitor<FunctionDeclBuilder> {
102102
// Get existing itype string from constraint variables.
103103
std::string getExistingIType(ConstraintVariable *DeclC);
104104

105-
virtual void buildDeclVar(const FVComponentVariable *CV, DeclaratorDecl *Decl,
106-
std::string &Type, std::string &IType,
107-
std::string UseName, bool &RewriteParm,
105+
virtual void buildDeclVar(const FVComponentVariable *CV,
106+
DeclaratorDecl *Decl, std::string &Type,
107+
std::string &IType, std::string UseName,
108+
bool &RewriteGen, bool &RewriteParm,
108109
bool &RewriteRet, bool StaticFunc);
109110
void buildCheckedDecl(PVConstraint *Defn, DeclaratorDecl *Decl,
110111
std::string &Type, std::string &IType,

clang/include/clang/3C/ProgramInfo.h

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,40 @@ class ProgramVariableAdder {
4343

4444
typedef std::pair<CVarSet, BKeySet> CSetBkeyPair;
4545

46+
// The pair of CVs are the type param constraint and an optional
47+
// constraint used to get the generic index. A better solution would have
48+
// generic constraints saved within ConstraintVariables, but those don't
49+
// exist at this time.
50+
struct TypeParamConstraint {
51+
ConstraintVariable *MainConstraint;
52+
ConstraintVariable *GenericAddition;
53+
TypeParamConstraint() :
54+
MainConstraint(nullptr), GenericAddition(nullptr) {}
55+
TypeParamConstraint(ConstraintVariable *M, ConstraintVariable *G) :
56+
MainConstraint(M), GenericAddition(G) {}
57+
// Fast. Whether `getConstraint` will return something other than nullptr.
58+
bool isConsistent() const { return MainConstraint != nullptr; }
59+
// Provides generic information if available and safe. This is somewhat of
60+
// a hack for nested generics and returns (the constraint for) a local
61+
// parameter. Otherwise, returns the generated constraint, which can also be
62+
// accessed as `MainConstraint`.
63+
ConstraintVariable *getConstraint(const EnvironmentMap &E) {
64+
if (MainConstraint != nullptr && GenericAddition != nullptr &&
65+
GenericAddition->isSolutionChecked(E)) {
66+
return GenericAddition;
67+
} else {
68+
return MainConstraint;
69+
}
70+
}
71+
};
72+
4673
class ProgramInfo : public ProgramVariableAdder {
4774
public:
48-
typedef std::map<unsigned int, ConstraintVariable *> CallTypeParamBindingsT;
75+
76+
// This map holds similar information as the type variable map in
77+
// ConstraintBuilder.cpp, but it is stored in a form that is usable during
78+
// rewriting.
79+
typedef std::map<unsigned int, TypeParamConstraint> CallTypeParamBindingsT;
4980

5081
typedef std::map<std::string, FVConstraint *> ExternalFunctionMapType;
5182
typedef std::map<std::string, ExternalFunctionMapType> StaticFunctionMapType;
@@ -119,7 +150,8 @@ class ProgramInfo : public ProgramVariableAdder {
119150
}
120151

121152
void setTypeParamBinding(CallExpr *CE, unsigned int TypeVarIdx,
122-
ConstraintVariable *CV, ASTContext *C);
153+
ConstraintVariable *CV,
154+
ConstraintVariable* Ident, ASTContext *C);
123155
bool hasTypeParamBindings(CallExpr *CE, ASTContext *C) const;
124156
const CallTypeParamBindingsT &getTypeParamBindings(CallExpr *CE,
125157
ASTContext *C) const;
@@ -217,11 +249,6 @@ class ProgramInfo : public ProgramVariableAdder {
217249
// used as keys for maps from ASTNodes.
218250
std::map<ASTContext *, unsigned int> TranslationUnitIdxMap;
219251

220-
// Special-case handling for decl introductions. For the moment this covers:
221-
// * void-typed variables
222-
// * va_list-typed variables
223-
void specialCaseVarIntros(ValueDecl *D, ASTContext *Context);
224-
225252
// Inserts the given FVConstraint set into the extern or static function map.
226253
// Returns the merged version if it was a redeclaration, or the constraint
227254
// parameter if it was new.

clang/include/clang/3C/RewriteUtils.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,23 @@ class FunctionDeclReplacement
8484
DeclReplacement::DRK_FunctionDecl> {
8585
public:
8686
explicit FunctionDeclReplacement(FunctionDecl *D, std::string R, bool Return,
87-
bool Params)
88-
: DeclReplacementTempl(D, nullptr, R), RewriteReturn(Return),
89-
RewriteParams(Params) {
87+
bool Params, bool Generic = false)
88+
: DeclReplacementTempl(D, nullptr, R), RewriteGeneric(Generic),
89+
RewriteReturn(Return), RewriteParams(Params) {
9090
assert("Doesn't make sense to rewrite nothing!" &&
91-
(RewriteReturn || RewriteParams));
91+
(RewriteGeneric || RewriteReturn || RewriteParams));
9292
}
9393

9494
SourceRange getSourceRange(SourceManager &SM) const override;
9595

9696
private:
9797
// This determines if the full declaration or the return will be replaced.
98+
bool RewriteGeneric;
9899
bool RewriteReturn;
99100
bool RewriteParams;
100101

101102
SourceLocation getDeclBegin(SourceManager &SM) const;
103+
SourceLocation getReturnBegin(SourceManager &SM) const;
102104
SourceLocation getParamBegin(SourceManager &SM) const;
103105
SourceLocation getReturnEnd(SourceManager &SM) const;
104106
SourceLocation getDeclEnd(SourceManager &SM) const;

clang/include/clang/3C/TypeVariableAnalysis.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ class TypeVariableEntry {
2020
public:
2121
// Note: does not initialize TyVarType!
2222
TypeVariableEntry() : IsConsistent(false), TypeParamConsVar(nullptr) {}
23-
TypeVariableEntry(QualType Ty, std::set<ConstraintVariable *> &CVs,
24-
bool ForceInconsistent = false)
23+
TypeVariableEntry(QualType Ty, std::set<ConstraintVariable *> &CVs
24+
, bool ForceInconsistent = false
25+
, ConstraintVariable *IdentCV = nullptr)
2526
: TypeParamConsVar(nullptr) {
2627
// We'll need a name to provide the type arguments during rewriting, so no
2728
// anonymous types are allowed.
@@ -30,6 +31,7 @@ class TypeVariableEntry {
3031
!isTypeAnonymous(Ty->getPointeeOrArrayElementType());
3132
TyVarType = Ty;
3233
ArgConsVars = CVs;
34+
GenArgumentCV = IdentCV;
3335
}
3436

3537
bool getIsConsistent() const;
@@ -38,10 +40,12 @@ class TypeVariableEntry {
3840
// Note: undefined behaviour if `getIsConsistent` is false
3941
std::set<ConstraintVariable *> &getConstraintVariables();
4042
ConstraintVariable *getTypeParamConsVar();
43+
ConstraintVariable *getGenArgCV();
4144

4245
void insertConstraintVariables(std::set<ConstraintVariable *> &CVs);
4346
void setTypeParamConsVar(ConstraintVariable *CV);
44-
void updateEntry(QualType Ty, std::set<ConstraintVariable *> &CVs);
47+
void updateEntry(QualType Ty, std::set<ConstraintVariable *> &CVs,
48+
ConstraintVariable *IdentCV);
4549

4650
private:
4751
// Is this type variable instantiated consistently. True when all uses have
@@ -61,6 +65,12 @@ class TypeVariableEntry {
6165
// A single constraint variable for solving the checked type of the type
6266
// variable. It is constrained GEQ all elements of ArgConsVars.
6367
ConstraintVariable *TypeParamConsVar;
68+
69+
// If an argument is a single identifier, store the constraint variable
70+
// to recognize changes in type from inferred generics. Null otherwise.
71+
// Meaningless if `TypeParamConsVar` has a basetype other than void, and
72+
// when we have generic index constraints, those should be favored over this
73+
ConstraintVariable *GenArgumentCV;
6474
};
6575

6676
// Stores the instantiated type for each type variables. This map has
@@ -100,7 +110,8 @@ class TypeVarVisitor : public RecursiveASTVisitor<TypeVarVisitor>,
100110
ConstraintResolver CR;
101111
TypeVariableMapT TVMap;
102112

103-
void insertBinding(CallExpr *CE, const int TyIdx, QualType Ty, CVarSet &CVs);
113+
void insertBinding(CallExpr *CE, const int TyIdx, QualType Ty,
114+
CVarSet &CVs, ConstraintVariable *IdentCV = nullptr);
104115
};
105116

106117
bool typeArgsProvided(CallExpr *Call);

clang/lib/3C/CastPlacement.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,11 @@ bool CastPlacementVisitor::VisitCallExpr(CallExpr *CE) {
5757
Expr *ArgExpr = A;
5858
if (FD && PIdx < FD->getNumParams()) {
5959
const int TyVarIdx = FV->getExternalParam(PIdx)->getGenericIndex();
60-
if (TypeVars.find(TyVarIdx) != TypeVars.end() &&
61-
TypeVars[TyVarIdx] != nullptr)
62-
TypeVar = TypeVars[TyVarIdx];
60+
// Check if local type vars are available
61+
if (TypeVars.find(TyVarIdx) != TypeVars.end()) {
62+
TypeVar = TypeVars[TyVarIdx].getConstraint(
63+
Info.getConstraints().getVariables());
64+
}
6365
}
6466
if (TypeVar != nullptr)
6567
ArgExpr = ArgExpr->IgnoreImpCasts();

clang/lib/3C/CheckedRegions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ bool CheckedRegionFinder::VisitCallExpr(CallExpr *C) {
230230
if (FD) {
231231
if (Info.hasTypeParamBindings(C, Context))
232232
for (auto Entry : Info.getTypeParamBindings(C, Context))
233-
Wild |= (Entry.second == nullptr);
233+
Wild |= !Entry.second.isConsistent();
234234
auto Type = FD->getReturnType();
235235
Wild |= (!(FD->hasPrototype() || FD->doesThisDeclarationHaveABody())) ||
236236
containsUncheckedPtr(Type);

clang/lib/3C/ConstraintBuilder.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ class FunctionVisitor : public RecursiveASTVisitor<FunctionVisitor> {
166166
// Is cast compatible with LHS type?
167167
QualType SrcT = C->getSubExpr()->getType();
168168
QualType DstT = C->getType();
169-
if (!isCastSafe(DstT, SrcT) && !Info.hasPersistentConstraints(C, Context)) {
169+
if (!CB.isCastofGeneric(C) && !isCastSafe(DstT, SrcT)
170+
&& !Info.hasPersistentConstraints(C, Context)) {
170171
auto CVs = CB.getExprConstraintVarsSet(C->getSubExpr());
171172
std::string Rsn =
172173
"Cast from " + SrcT.getAsString() + " to " + DstT.getAsString();

0 commit comments

Comments
 (0)