Skip to content

Adds (De)Serialization of Declaration Bounds #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,10 @@ void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
VisitValueDecl(DD);
DD->setInnerLocStart(ReadSourceLocation(Record, Idx));

if (Record[Idx++]) // hasBoundsExpr
DD->setBoundsExpr(Reader.ReadBoundsExpr(F));

if (Record[Idx++]) { // hasExtInfo
DeclaratorDecl::ExtInfo *Info
= new (Reader.getContext()) DeclaratorDecl::ExtInfo();
Expand Down
15 changes: 15 additions & 0 deletions lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,11 @@ void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
VisitValueDecl(D);
Record.AddSourceLocation(D->getInnerLocStart());

Record.push_back(D->hasBoundsExpr());
if (D->hasBoundsExpr())
Record.AddStmt(D->getBoundsExpr());

Record.push_back(D->hasExtInfo());
if (D->hasExtInfo())
Record.AddQualifierInfo(*D->getExtInfo());
Expand Down Expand Up @@ -728,6 +733,7 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
!D->isReferenced() &&
!D->isModulePrivate() &&
!D->getBitWidth() &&
!D->hasBoundsExpr() &&
!D->hasExtInfo() &&
D->getDeclName())
AbbrevToUse = Writer.getDeclObjCIvarAbbrev();
Expand Down Expand Up @@ -862,6 +868,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
!D->isModulePrivate() &&
!D->getBitWidth() &&
!D->hasInClassInitializer() &&
!D->hasBoundsExpr() &&
!D->hasExtInfo() &&
!ObjCIvarDecl::classofKind(D->getKind()) &&
!ObjCAtDefsFieldDecl::classofKind(D->getKind()) &&
Expand Down Expand Up @@ -940,6 +947,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->isModulePrivate() &&
!needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasBoundsExpr() &&
!D->hasExtInfo() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
D->getInitStyle() == VarDecl::CInit &&
Expand Down Expand Up @@ -980,6 +988,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
// know are true of all PARM_VAR_DECLs.
if (D->getDeclContext() == D->getLexicalDeclContext() &&
!D->hasAttrs() &&
!D->hasBoundsExpr() &&
!D->hasExtInfo() &&
!D->isImplicit() &&
!D->isUsed(false) &&
Expand Down Expand Up @@ -1235,6 +1244,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
!D->hasAttrs() &&
!D->isTopLevelDeclInObjCContainer() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasBoundsExpr() &&
!D->hasExtInfo() &&
!D->hasInheritedPrototype() &&
D->hasWrittenPrototype())
Expand Down Expand Up @@ -1714,6 +1724,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasBoundsExpr
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// FieldDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
Expand Down Expand Up @@ -1747,6 +1758,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasBoundsExpr
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// FieldDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
Expand Down Expand Up @@ -1878,6 +1890,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasBoundsExpr
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
Expand Down Expand Up @@ -1954,6 +1967,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasBoundsExpr
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
Expand Down Expand Up @@ -2002,6 +2016,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerLocStart
Abv->Add(BitCodeAbbrevOp(0)); // hasBoundsExpr
Abv->Add(BitCodeAbbrevOp(0)); // HasExtInfo
// FunctionDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // IDNS
Expand Down
120 changes: 84 additions & 36 deletions test/CheckedC/pch.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,60 +10,108 @@
// RUN: %clang_cc1 -fcheckedc-extension -emit-pch -o %t %S/pch.h
// RUN: %clang_cc1 -fcheckedc-extension -include-pch %t -fsyntax-only -verify -verify-ignore-unexpected=note %s

// Bounds Expressions on globals
//
// Bounds Expressions on global variables
//

// CountBounds
one_element_array arr1 = (int[1]){ 0 };
_Array_ptr<int> one_arr : count(1 + 1); // expected-error{{variable redeclaration has conflicting bounds}}
_Array_ptr<int> one_arr : count(1);

// Byte Count
_Array_ptr<int> byte_arr : byte_count(sizeof(int));

// NullaryBounds
null_array arr2 = (int[]){ 0 };
_Array_ptr<int> null_arr : count(1); // expected-error{{variable redeclaration has conflicting bounds}}
_Array_ptr<int> null_arr : bounds(none);

// RangeBounds
ranged_array arr3 = two_arr;
int two_arr[2];
_Array_ptr<int> ranged_arr : bounds(&one_arr, &one_arr + 1); //expected-error{{variable redeclaration has conflicting bounds}}
_Array_ptr<int> ranged_arr : bounds(&two_arr, &two_arr + 1);

// InteropTypeBoundsAnnotation
int seven = 7;
integer_pointer seven_pointer1 = &seven;
_Ptr<int> seven_pointer2 = &seven;
int* int_ptr : itype(_Array_ptr<int>); // expected-error{{variable redeclaration has conflicting bounds}}
int* int_ptr : itype(_Ptr<int>);
int* int_ptr;

//
// Bounds Expressions on functions
int accepts_singleton(_Array_ptr<int> one_arr : count(1)) {
return one_arr[0];
}
void uses_accepts_singleton(void) {
_Array_ptr<int> singleton : count(1) = (int[1]) { 0 };
int x = accepts_singleton(singleton);
}
//

// CountBounds
int count_fn(_Array_ptr<int> arr : count(2)); // expected-error{{function redeclaration has conflicting parameter bounds}}
int count_fn(_Array_ptr<int> arr : count(1));
_Array_ptr<int> count_fn2(void) : count(2); // expected-error{{function redeclaration has conflicting return bounds}}
_Array_ptr<int> count_fn2(void) : count(1);

// Byte Count
int byte_count_fn(_Array_ptr<int> arr : byte_count(sizeof(int) + 1)); // expected-error{{function redeclaration has conflicting parameter bounds}}
int byte_count_fn(_Array_ptr<int> arr : byte_count(sizeof(int)));
_Array_ptr<int> byte_count_fn2(void) : byte_count(sizeof(int) + 1); // expected-error{{function redeclaration has conflicting return bounds}}
_Array_ptr<int> byte_count_fn2(void) : byte_count(sizeof(int));

// NullaryBounds
int none_fn(_Array_ptr<int> null_arr : count(1)); // expected-error{{function redeclaration has conflicting parameter bounds}}
int none_fn(_Array_ptr<int> null_arr : bounds(none));
_Array_ptr<int> none_fn2(void) : count(1); // expected-error{{function redeclaration has conflicting return bounds}}
_Array_ptr<int> none_fn2(void) : bounds(none);

// RangeBounds + PositionalParamater
int sum_array(_Array_ptr<int> start : bounds(start, end), _Array_ptr<int> end) {
return 0;
int range_fn(_Array_ptr<int> start : bounds(start, end - 1), _Array_ptr<int> end); // expected-error{{function redeclaration has conflicting parameter bounds}}
int range_fn(_Array_ptr<int> start : bounds(start, end), _Array_ptr<int> end);
_Array_ptr<int> range_fn2(_Array_ptr<int> start) : bounds(start, start + 1); // expected-error{{function redeclaration has conflicting return bounds}}
_Array_ptr<int> range_fn2(_Array_ptr<int> start) : bounds(start, start);

// CountBounds + PositionalParameter
int pos_fn(int len, _Array_ptr<char> str : count(len + 1)); // expected-error{{function redeclaration has conflicting parameter bounds}}
int pos_fn(int len, _Array_ptr<char> str : count(len));
_Array_ptr<int> pos_fn2(int len) : count(len + 1); // expected-error{{function redeclaration has conflicting return bounds}}
_Array_ptr<int> pos_fn2(int len) : count(len);

// InteropTypeBoundsAnnotation
int int_val(int *ptr : itype(_Array_ptr<int>)); // expected-error{{function redeclaration has conflicting parameter bounds}}
int int_val(int *ptr : itype(_Ptr<int>));
int int_val(int *ptr);
int* int_val2(void) : itype(_Array_ptr<int>); // expected-error{{function redeclaration has conflicting return bounds}}
int* int_val2(void) : itype(_Ptr<int>);
int* int_val2(void);


//
// Bounds Expressions on Struct Members
//

// CountBounds
struct S1;
void uses_S1(struct S1 data) {
_Array_ptr<int> arr : count(5) = data.arr;
}
void uses_sum_array(void) {
_Array_ptr<int> pair : count(2) = (int[2]) { 0,1 };
int x = sum_array(pair, pair+1);

// Byte Count
struct S2;
void uses_S2(struct S2 data) {
_Array_ptr<int> arr : byte_count(sizeof(int) * 5) = data.arr;
}

// PositionalParameter
int str_last(int len, _Array_ptr<char> str : count(len)) {
return 0;
// NullaryBounds
struct S3;
void uses_S3(struct S3 data) {
_Array_ptr<int> arr : bounds(none) = data.arr;
}
void uses_str_last(void) {
_Array_ptr<char> str : count(3) = (char[3]){ 'a', 'b', 'c' };
int last = str_last(3, str);

// RangeBounds
struct S4;
void uses_S4(struct S4 data) {
_Array_ptr<long> arr : bounds(data.arr, data.arr + 5) = data.arr;
}

// InteropTypeBoundsAnnotation
int int_val(int *ptr : itype(_Ptr<int>)) {
return 0;
}
void uses_int_val(void) {
struct S5;
void uses_S5(struct S5 data) {
// Tests assigning a `_Ptr<int>` into an `int* : itype(_Ptr<int>)`
// This should be valid, according to the spec.
int i = 3;
_Ptr<int> i_star = &i;
int i2 = int_val(i_star);
}

// Dropping bounds errors
int accepts_pair(_Array_ptr<int> two_arr) { // expected-error{{function redeclaration dropped bounds for parameter}}
return 3;
_Ptr<int> ip = &i;
data.i = ip;
}
67 changes: 53 additions & 14 deletions test/CheckedC/pch.h
Original file line number Diff line number Diff line change
@@ -1,39 +1,78 @@
// Used with the pch.c test

// Bounds Expressions on globals
//
// Bounds Expressions on global variables
//

// CountBounds
_Array_ptr<int> one_arr : count(1);
typedef typeof(one_arr) one_element_array;

// Byte Count
_Array_ptr<int> byte_arr : byte_count(sizeof(int));

// NullaryBounds
_Array_ptr<int> null_arr : bounds(none);
typedef typeof(null_arr) null_array;

// RangeBounds
int two_arr[2] = { 0, 0 };
int two_arr[2];
_Array_ptr<int> ranged_arr : bounds(&two_arr, &two_arr + 1);
typedef typeof(ranged_arr) ranged_array;

// InteropTypeBoundsAnnotation
int* int_ptr : itype(_Ptr<int>);
typedef typeof(int_ptr) integer_pointer;


//
// Bounds Expressions on functions
int accepts_singleton(_Array_ptr<int> one_arr : count(1));
//

// CountBounds
int count_fn(_Array_ptr<int> arr : count(1));
_Array_ptr<int> count_fn2(void) : count(1);

// Byte Count
int byte_count_fn(_Array_ptr<int> arr : byte_count(sizeof(int)));
_Array_ptr<int> byte_count_fn2(void) : byte_count(sizeof(int));

// NullaryBounds
int accepts_null(_Array_ptr<int> null_arr : bounds(none));
int none_fn(_Array_ptr<int> null_arr : bounds(none));
_Array_ptr<int> none_fn2(void) : bounds(none);

// RangeBounds + PositionalParameter
int sum_array(_Array_ptr<int> start : bounds(start, end) , _Array_ptr<int> end);
int range_fn(_Array_ptr<int> start : bounds(start, end), _Array_ptr<int> end);
_Array_ptr<int> range_fn2(_Array_ptr<int> start) : bounds(start, start);

// PositionalParameter
int str_last(int len, _Array_ptr<char> str : count(len));
// CountBounds + PositionalParameter
int pos_fn(int len, _Array_ptr<char> str : count(len));
_Array_ptr<int> pos_fn2(int len) : count(len);

// InteropTypeBoundsAnnotation
int int_val(int *ptr : itype(_Ptr<int>));
int* int_val2(void) : itype(_Ptr<int>);

//
// Bounds Expressions on Struct Members
//

// CountBounds
struct S1 {
_Array_ptr<int> arr : count(5);
};

// Byte Count
struct S2 {
_Array_ptr<int> arr : byte_count(sizeof(int) * 5);
};

// NullaryBounds
struct S3 {
_Array_ptr<int> arr : bounds(none);
};

// dropping bounds errors
int accepts_pair(_Array_ptr<int> two_arr : count(2));
// RangeBounds
struct S4 {
_Array_ptr<long> arr : bounds(arr, arr + 5);
};

// InteropTypeBoundsAnnotation
struct S5 {
int* i : itype(_Ptr<int>);
};