diff --git a/clang/lib/3C/ConstraintVariables.cpp b/clang/lib/3C/ConstraintVariables.cpp index 6d5751a4c423..a90c8d5103cf 100644 --- a/clang/lib/3C/ConstraintVariables.cpp +++ b/clang/lib/3C/ConstraintVariables.cpp @@ -280,7 +280,16 @@ PointerVariableConstraint::PointerVariableConstraint( SourceRange R = ITE->getSourceRange(); if (R.isValid()) { ItypeStr = getSourceText(R, C); - assert(ItypeStr.size() > 0); + } + + // ITE->isCompilerGenerated will be true when an itype expression is + // implied by a bounds expression on the declaration. When the itype + // expression is not generated by the compiler, but we failed to extract + // its string representation from the source, build the itype string + // from the AST. + if (!ITE->isCompilerGenerated() && ItypeStr.empty()) { + assert(!InteropType.getAsString().empty()); + ItypeStr = "itype(" + InteropType.getAsString() + ")"; } } } diff --git a/clang/test/3C/macro_itype.c b/clang/test/3C/macro_itype.c new file mode 100644 index 000000000000..fd138524d6fa --- /dev/null +++ b/clang/test/3C/macro_itype.c @@ -0,0 +1,34 @@ +// RUN: rm -rf %t* +// RUN: 3c -base-dir=%S -alltypes -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ALL","CHECK" %s +// RUN: 3c -base-dir=%S -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_NOALL","CHECK" %s +// RUN: 3c -base-dir=%S -alltypes -addcr %s -- | %clang -c -fcheckedc-extension -x c -o /dev/null - +// RUN: 3c -base-dir=%S -alltypes -output-dir=%t.checked %s -- +// RUN: 3c -base-dir=%t.checked -alltypes %t.checked/macro_itype.c -- | diff %t.checked/macro_itype.c - + +// Example encountered while converting libjpeg. This triggered an assertion +// fail because the ItypeStr extracted from the source was empty. +#define macro0 int *a : itype(_Ptr); +struct s { macro0 }; +//CHECK: struct s { macro0 }; + +// Example from issue correctcomputation/checkedc-clang#594. +#define PARAM_DECL_WITH_ITYPE int *p : itype(_Ptr) +void foo(PARAM_DECL_WITH_ITYPE); +//CHECK: void foo(PARAM_DECL_WITH_ITYPE); + +// Just removing the assertion that failed on the above example caused this to +// rewrite incorrectly. The ItypeStr would be left empty, so first parameter +// would be rewritten to `int *b` even though the rewriter intended to give it +// an itype. If the parameter was then passed a checked pointer, there would be +// a Checked C compiler error. Ideally, 3C wouldn't need to change the +// declaration of `b` at all (see issue correctcomputation/checkedc-clang#694). +#define macro1 : itype(_Ptr) +void fn(int *b macro1, int *c) { +//CHECK: void fn(int *b : itype(_Ptr), _Ptr c) { + b = 1; +} +void caller() { + int *e; + //CHECK: _Ptr e = ((void *)0); + fn(e, 0); +} diff --git a/clang/test/3C/params_in_macro.c b/clang/test/3C/params_in_macro.c index 1850419d6fff..ceaabe58f967 100644 --- a/clang/test/3C/params_in_macro.c +++ b/clang/test/3C/params_in_macro.c @@ -11,14 +11,11 @@ typedef double mydouble; -// TODO: FunctionDeclBuilder::buildDeclVar should be able to handle an itype -// here, but currently the PointerConstraintVariable constructor asserts when it -// fails to retrieve the original source of the itype declaration. #define parms1 volatile mydouble d, void (*f)(void) -#define parms2 int *const y : count(7), _Ptr z +#define parms2 int *const y : count(7), _Ptr z, int *zz : itype(_Ptr) void test(parms1, int *x, parms2) {} -// CHECK: void test(volatile mydouble d, void (*f)(void), _Ptr x, int *const y : count(7), _Ptr z) {} +// CHECK: void test(volatile mydouble d, void (*f)(void), _Ptr x, int *const y : count(7), _Ptr z, int *zz : itype(_Ptr)) {} // Before the bug fix, we got: -// void test(, , _Ptr x, , ) {} +// void test(, , _Ptr x, , , ) {}