Skip to content

Commit 4dc7631

Browse files
author
Prabhuk
authored
Add support for polymorphic bounds safe interface functions (#546)
1. Parsing code to identify our new checked c keyword "_Itype_for_any" is added. 2. Design document md file added for _Itype_for_any implementation details 3. Parser now treats void * and pointer to TypeVariableType as equivalent types when the TypeVariableType is encountered under the _Itype_for_any scope. 4. "_Itype_for_any" are now compatible with declarations of non bounds safe generic function allowing redeclaration of interface funcions with _Itype_for_any specifier and type variables. 5. Parsing of calls to itype generic functions from checked scope now expects types to be provided. 6. This is optional for calls from unchecked scope.
1 parent 3fe8938 commit 4dc7631

24 files changed

Lines changed: 373 additions & 116 deletions
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
**Function Specifier for Bounds Safe Interfaces:**
2+
3+
*itype_for_any(<COMMA_SEPARATED_TYPE_VARIABLES>)*
4+
5+
* Creates a new scope
6+
* Restrictions on parameters:
7+
* No type variable can be used as the type of function parameters
8+
* Type variables of parameters must be contained within itype clauses
9+
* e.g.
10+
`itype_for_any(T)
11+
void* foo(void* arg1 : itype(_Ptr<T>));`
12+
* There are no restrictions on local variables
13+
* i.e., Typevariables can be used as the type of local variables created within function body; even if the scope is unchecked.
14+
* itype_for_any and for_any scopes cannot be nested
15+
* Design discussion with David MoM:
16+
* The bounds interface function will have a polymorphic type associated with it
17+
* If the caller doesn't apply a type, then the default type of the parameters will be applied as types
18+
* e.g
19+
* For the foo function shown above, the caller `foo<int>(x)` will force arg1 to be a pointer to int
20+
* But the caller `foo(y)` will treat arg1 as pointer to void type
21+
* This design is to enable foo to be called from unchecked scopes to allow incremental adoption
22+
23+
24+

include/clang/AST/ASTContext.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,10 +1198,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
11981198
/// pointer to blocks.
11991199
QualType getBlockDescriptorExtendedType() const;
12001200

1201-
/// Returns a type variable type based on the depth of the "for any" scope
1202-
/// where type variable is declared, and the position of the type variable in
1203-
/// _For_any qualifier.
1204-
QualType getTypeVariableType(unsigned int depth, unsigned int position) const;
1201+
/// Returns a type variable type based on the depth of "for any" or
1202+
/// "itype for any" scope where type variable is declared, and the
1203+
/// position of the type variable in _For_any or _Itype_for_any
1204+
///.qualifier respectively
1205+
QualType getTypeVariableType(unsigned int depth, unsigned int position,
1206+
bool isBoundsInterfaceType) const;
12051207

12061208
void setcudaConfigureCallDecl(FunctionDecl *FD) {
12071209
cudaConfigureCallDecl = FD;
@@ -2486,12 +2488,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
24862488
/// at least as much checking as the other type T2. Return true if it does
24872489
/// or false if it does not or the types differ in some other way than
24882490
/// checkedness.
2491+
/// Note:: In bounds safe interface scopes, this function
2492+
/// returns true if T1 is a TypeVariableType and T2 is a pointer to void type
24892493
bool isAtLeastAsCheckedAs(QualType T1, QualType T2) const;
24902494

24912495
/// \brief Determine whether a pointer, array, or function type T1
24922496
/// is the same as the other pointer, array, or function type T2 if
24932497
/// checkedness is ignored. Return true if does or false if the types
24942498
/// differ in some other way than checkedness.
2499+
/// Note:: In bounds safe interface scopes, this function
2500+
/// returns true if T1 is a TypeVariableType and T2 is a pointer to void type
24952501
bool isEqualIgnoringChecked(QualType T1, QualType T2) const;
24962502

24972503
/// \brief Return true if this type is a checked type that is not

include/clang/AST/Decl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
17891789
unsigned IsLateTemplateParsed : 1;
17901790
unsigned IsConstexpr : 1;
17911791
unsigned IsGenericFunction : 1;
1792+
unsigned IsItypeGenericFunction : 1; //Checked C - Function specifier _Itype_for_any
17921793
// Indicates whether the function is declared with a _Checked or
17931794
// _Unchecked specifier.
17941795
unsigned CheckedSpecifier : 2;
@@ -1896,7 +1897,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
18961897
IsDeleted(false), IsTrivial(false), IsDefaulted(false),
18971898
IsExplicitlyDefaulted(false), HasImplicitReturnZero(false),
18981899
IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
1899-
IsGenericFunction(false),
1900+
IsGenericFunction(false), IsItypeGenericFunction(false),
19001901
CheckedSpecifier(CheckedFunctionSpecifiers::CFS_None),
19011902
InstantiationIsPending(false),
19021903
UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false),
@@ -1964,6 +1965,9 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
19641965
void setGenericFunctionFlag(bool f) { IsGenericFunction = f; }
19651966
bool isGenericFunction() const { return IsGenericFunction; }
19661967

1968+
void setItypeGenericFunctionFlag(bool f) { IsItypeGenericFunction = f; }
1969+
bool isItypeGenericFunction() const { return IsItypeGenericFunction; }
1970+
19671971
void setCheckedSpecifier(CheckedFunctionSpecifiers CS) { CheckedSpecifier = CS; }
19681972
CheckedFunctionSpecifiers getCheckedSpecifier() {
19691973
return (CheckedFunctionSpecifiers) CheckedSpecifier;

include/clang/AST/Type.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3429,12 +3429,14 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
34293429
/// Extra information about a function prototype.
34303430
struct ExtProtoInfo {
34313431
ExtProtoInfo()
3432-
: Variadic(false), HasTrailingReturn(false), numTypeVars(0),
3432+
: Variadic(false), HasTrailingReturn(false), numTypeVars(0),
3433+
GenericFunction(false), ItypeGenericFunction(false),
34333434
TypeQuals(0), RefQualifier(RQ_None), ExtParameterInfos(nullptr),
34343435
ParamAnnots(nullptr), ReturnAnnots() {}
34353436

34363437
ExtProtoInfo(CallingConv CC)
3437-
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false), numTypeVars(0),
3438+
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false), numTypeVars(0),
3439+
GenericFunction(false), ItypeGenericFunction(false),
34383440
TypeQuals(0), RefQualifier(RQ_None), ExtParameterInfos(nullptr),
34393441
ParamAnnots(nullptr), ReturnAnnots() {}
34403442

@@ -3448,6 +3450,8 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
34483450
bool Variadic : 1;
34493451
bool HasTrailingReturn : 1;
34503452
unsigned numTypeVars : 15;
3453+
bool GenericFunction : 1;
3454+
bool ItypeGenericFunction : 1;
34513455
unsigned char TypeQuals;
34523456
RefQualifierKind RefQualifier;
34533457
ExceptionSpecInfo ExceptionSpec;
@@ -3487,6 +3491,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
34873491
/// Whether the function is variadic.
34883492
unsigned Variadic : 1;
34893493

3494+
bool GenericFunction : 1;
3495+
bool ItypeGenericFunction : 1;
3496+
34903497
/// Whether this function has a trailing return type.
34913498
unsigned HasTrailingReturn : 1;
34923499

@@ -3553,6 +3560,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
35533560
return param_type_begin()[i];
35543561
}
35553562
unsigned getNumTypeVars() const { return NumTypeVars; }
3563+
bool isGenericFunction() const { return GenericFunction; }
3564+
bool isItypeGenericFunction() const { return ItypeGenericFunction; }
3565+
35563566
ArrayRef<QualType> getParamTypes() const {
35573567
return llvm::makeArrayRef(param_type_begin(), param_type_end());
35583568
}
@@ -3588,6 +3598,8 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
35883598
EPI.ParamAnnots = hasParamAnnots() ? param_annots_begin() : nullptr;
35893599
EPI.ReturnAnnots = getReturnAnnots();
35903600
EPI.numTypeVars = getNumTypeVars();
3601+
EPI.GenericFunction = isGenericFunction();
3602+
EPI.ItypeGenericFunction = isItypeGenericFunction();
35913603
return EPI;
35923604
}
35933605

@@ -3835,10 +3847,11 @@ class TypeVariableType : public Type, public llvm::FoldingSetNode {
38353847
// prototype scope depth, this keeps track of the depth of forany scope.
38363848
unsigned int depth;
38373849
unsigned int index;
3850+
bool isBoundsInterfaceType;
38383851
protected:
3839-
TypeVariableType(unsigned int inDepth, unsigned int inIndex)
3852+
TypeVariableType(unsigned int inDepth, unsigned int inIndex, bool inBoundsInterface)
38403853
: Type(TypeVariable, QualType(), false, false, false, false),
3841-
depth(inDepth), index(inIndex) { }
3854+
depth(inDepth), index(inIndex), isBoundsInterfaceType(inBoundsInterface) { }
38423855
friend class ASTContext;
38433856
public:
38443857
bool isSugared(void) const { return false; }
@@ -3847,6 +3860,12 @@ class TypeVariableType : public Type, public llvm::FoldingSetNode {
38473860
void SetDepth(unsigned int i) { depth = i; }
38483861
unsigned int GetIndex(void) const { return index; }
38493862
void SetIndex(unsigned int i) { index = i; }
3863+
void SetInBoundsInterface (bool isInBoundsInterface) {
3864+
isBoundsInterfaceType = isInBoundsInterface;
3865+
}
3866+
bool IsBoundsInterfaceType () const {
3867+
return isBoundsInterfaceType;
3868+
}
38503869

38513870
void Profile(llvm::FoldingSetNodeID &ID) {
38523871
Profile(ID, depth, index);

include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,10 +1201,10 @@ def err_forany_type_variable_declaration_expected : Error<
12011201
def err_forany_type_variable_identifier_expected : Error<
12021202
"expected type variable identifier">;
12031203

1204-
def err_forany_unexpected_token : Error<
1205-
"unexpected token in _For_any specifier">;
1204+
def err_generic_specifier_unexpected_token : Error<
1205+
"unexpected token in %0 specifier">;
12061206

1207-
def err_forany_comma_or_parenthesis_expected : Error<
1207+
def err_generic_specifier_comma_or_parenthesis_expected : Error<
12081208
"expected , or )">;
12091209

12101210
def err_expected_list_of_types_expr_for_generic_function : Error<

include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9516,7 +9516,7 @@ def err_bounds_type_annotation_lost_checking : Error<
95169516
"bounds to have no prototype">;
95179517

95189518
def note_previous_bounds_decl : Note<"previous %select{bounds|interop type}0 declaration is here">;
9519-
9519+
95209520
def err_decl_conflicting_annot : Error<
95219521
"%select{function redeclaration has conflicting parameter %select{bounds|interop type}0|function "
95229522
"redeclaration has conflicting return %select{bounds|interop type}0|variable redeclaration has "
@@ -9533,6 +9533,9 @@ def err_bounds_type_annotation_lost_checking : Error<
95339533

95349534
def err_conflicting_annots : Error<"conflicting bounds annotations for %0">;
95359535

9536+
def err_decl_conflicting_function_specifiers : Error<
9537+
"conflicting function specifiers for %0. %1 and %2 are incompatible function specifiers.">;
9538+
95369539
def err_out_of_scope_function_type_local : Error<
95379540
"out-of-scope variable for bounds in a function type (a function type "
95389541
"cannot reference local variables)">;

include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ KEYWORD(_Unchecked , KEYCHECKEDC)
653653
KEYWORD(_Assume_bounds_cast , KEYCHECKEDC)
654654
KEYWORD(_Dynamic_bounds_cast , KEYCHECKEDC)
655655
KEYWORD(_For_any , KEYCHECKEDC)
656+
KEYWORD(_Itype_for_any , KEYCHECKEDC)
656657

657658
// Borland Extensions which should be disabled in strict conformance mode.
658659
ALIAS("_pascal" , __pascal , KEYBORLAND)

include/clang/Parse/Parser.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1764,7 +1764,8 @@ class Parser : public CodeCompletionHandler {
17641764
ExprResult ParseBoundsCastExpression();
17651765

17661766
ExprResult ParseBoundsExpression();
1767-
bool ParseGenericFunctionExpression(ExprResult &Res);
1767+
bool ParseItypeAndGenericFunctionExpression(ExprResult &Res);
1768+
17681769
QualType SubstituteTypeVariable(QualType QT,
17691770
SmallVector<DeclRefExpr::GenericInstInfo::TypeArgument, 4> &typeNames);
17701771

@@ -2486,6 +2487,9 @@ class Parser : public CodeCompletionHandler {
24862487
void ParseAtomicSpecifier(DeclSpec &DS);
24872488
void ParseCheckedPointerSpecifiers(DeclSpec & DS);
24882489
void ParseForanySpecifier(DeclSpec &DS);
2490+
bool ParseGenericFunctionSpecifierHelper(DeclSpec &DS,
2491+
Scope::ScopeFlags S);
2492+
void ParseItypeforanySpecifier(DeclSpec &DS);
24892493

24902494
ExprResult ParseAlignArgument(SourceLocation Start,
24912495
SourceLocation &EllipsisLoc);

include/clang/Sema/DeclSpec.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,8 @@ class DeclSpec {
366366
unsigned FS_checked_specified : 2;
367367
// Checked C - For-any function specifier
368368
unsigned FS_forany_specified : 1;
369+
// Checked C - _Itype_for_any function specifier
370+
unsigned FS_itypeforany_specified : 1;
369371

370372
// friend-specifier
371373
unsigned Friend_specified : 1;
@@ -387,6 +389,9 @@ class DeclSpec {
387389

388390
TypedefDecl **TypeVarInfo;
389391
unsigned NumTypeVars : 15;
392+
bool GenericFunction : 1;
393+
bool ItypeGenericFunction : 1;
394+
390395

391396
// Scope specifier for the type spec, if applicable.
392397
CXXScopeSpec TypeScope;
@@ -409,7 +414,7 @@ class DeclSpec {
409414
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
410415
SourceLocation FS_forceinlineLoc;
411416
// Checked C - checked keyword location
412-
SourceLocation FS_checkedLoc, FS_foranyLoc;
417+
SourceLocation FS_checkedLoc, FS_foranyLoc, FS_itypeforanyloc;
413418
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConceptLoc;
414419
SourceLocation TQ_pipeLoc;
415420

@@ -459,12 +464,15 @@ class DeclSpec {
459464
// Checked C - checked function
460465
FS_checked_specified(CFS_None),
461466
FS_forany_specified(false),
467+
FS_itypeforany_specified(false),
462468
Friend_specified(false),
463469
Constexpr_specified(false),
464470
Concept_specified(false),
465471
Attrs(attrFactory),
466472
TypeVarInfo(nullptr),
467473
NumTypeVars(0),
474+
GenericFunction(false),
475+
ItypeGenericFunction(false),
468476
writtenBS(),
469477
ObjCQualifiers(nullptr) {
470478
}
@@ -605,11 +613,16 @@ class DeclSpec {
605613
SourceLocation getCheckedSpecLoc() const { return FS_checkedLoc; }
606614

607615
bool isForanySpecified() const { return FS_forany_specified; }
616+
bool isItypeforanySpecified() const { return FS_itypeforany_specified; }
608617
SourceLocation getForanySpecLoc() const { return FS_foranyLoc; }
609618

610619
void setTypeVars(ASTContext &C, ArrayRef<TypedefDecl *> NewTypeVarInfo, unsigned NewNumTypeVars);
620+
void setGenericFunction(bool IsGeneric) { GenericFunction = IsGeneric; }
621+
void setItypeGenericFunction(bool IsItypeGeneric) { ItypeGenericFunction = IsItypeGeneric; }
611622
void setNumTypeVars(unsigned NewNumTypeVars) { NumTypeVars = NewNumTypeVars; }
612623
unsigned getNumTypeVars(void) const { return NumTypeVars; }
624+
bool isGenericFunction(void) const { return GenericFunction; }
625+
bool isItypeGenericFunction(void) const { return ItypeGenericFunction; }
613626

614627
ArrayRef<TypedefDecl *> typeVariables() const {
615628
return { TypeVarInfo, getNumTypeVars() };
@@ -633,6 +646,8 @@ class DeclSpec {
633646
FS_checkedLoc = SourceLocation();
634647
FS_forany_specified = false;
635648
FS_foranyLoc = SourceLocation();
649+
FS_itypeforany_specified = false;
650+
FS_itypeforanyloc= SourceLocation();
636651
}
637652

638653
/// \brief Return true if any type-specifier has been found.
@@ -742,6 +757,8 @@ class DeclSpec {
742757
unsigned &DiagID);
743758
bool setFunctionSpecForany(SourceLocation Loc, const char *&PrevSpec,
744759
unsigned &DiagID);
760+
bool setFunctionSpecItypeforany(SourceLocation Loc, const char *&PrevSpec,
761+
unsigned &DiagID);
745762
bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
746763
unsigned &DiagID);
747764
bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,

include/clang/Sema/Scope.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,10 @@ class Scope {
139139
UncheckedScope = 0x2000000,
140140

141141
/// Checked C - _For_any Polymorphic type scopes
142-
ForanyScope = 0x4000000
142+
ForanyScope = 0x4000000,
143+
144+
/// Checked C - _Itype_for_any Polymorphic bounds safe interface type scopes
145+
ItypeforanyScope = 0x8000000
143146

144147
};
145148
private:
@@ -347,6 +350,9 @@ class Scope {
347350
/// isForanyScope - Return true if this scope is _For_any scope.
348351
bool isForanyScope() const { return (getFlags() & Scope::ForanyScope); }
349352

353+
/// isItypeforanyScope - Return true if this scope is _Itype_for_any scope.
354+
bool isItypeforanyScope() const { return (getFlags() & Scope::ItypeforanyScope); }
355+
350356
/// isInCXXInlineMethodScope - Return true if this scope is a C++ inline
351357
/// method scope or is inside one.
352358
bool isInCXXInlineMethodScope() const {

0 commit comments

Comments
 (0)