Skip to content

Commit 872b2ca

Browse files
[BoundsSafety] Allow using bounds-attributed types when deducing auto
Allow using bounds-attributed types when deducing auto type in attribute-only mode. Since the bounds-attributed type can depend on a variable in a different scope etc., we drop the bounds-attributed sugar and emit a warning. rdar://140995829 (cherry picked from commit 4fe6dbb)
1 parent 3609dfb commit 872b2ca

File tree

5 files changed

+295
-43
lines changed

5 files changed

+295
-43
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13480,7 +13480,10 @@ def err_bounds_safety_ptrauth_on_indexable_pointer : Error<
1348013480

1348113481
def err_bounds_safety_auto_dynamic_bound : Error<
1348213482
"passing %select{'__counted_by'|'__sized_by'|'__counted_by_or_null'|'__sized_by_or_null'|'__ended_by'|end}0 pointer "
13483-
"as __auto_type initializer is not yet supported">;
13483+
"as %select{'auto'|'decltype(auto)'|'__auto_type'}1 initializer is not yet supported">;
13484+
def warn_bounds_safety_auto_dynamic_bound : Warning<
13485+
err_bounds_safety_auto_dynamic_bound.Summary>,
13486+
InGroup<DiagGroup<"bounds-safety-auto-bounds-attributed">>;
1348413487

1348513488
def err_bounds_safety_unsupported_address_of_incomplete_array : Error<
1348613489
"cannot take address of incomplete __counted_by array">;

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5167,6 +5167,44 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
51675167
return false;
51685168
}
51695169

5170+
// TO_UPSTREAM(BoundsSafety) ON
5171+
static bool CheckAutoCanInferTypeFromBoundsAttributed(Sema &S,
5172+
const AutoType *AT,
5173+
Expr *Init,
5174+
QualType &Result) {
5175+
if (!S.getLangOpts().BoundsSafetyAttributes)
5176+
return true;
5177+
5178+
QualType InitTy = Init->getType();
5179+
const auto *BATy = InitTy->getAs<BoundsAttributedType>();
5180+
if (!BATy)
5181+
return true;
5182+
5183+
QualType DesugaredTy;
5184+
unsigned Kind;
5185+
if (const auto *CATy = dyn_cast<CountAttributedType>(BATy)) {
5186+
DesugaredTy = CATy->desugar();
5187+
Kind = CATy->getKind();
5188+
} else {
5189+
const auto *DRPTy = cast<DynamicRangePointerType>(BATy);
5190+
DesugaredTy = DRPTy->desugar();
5191+
Kind = DRPTy->getEndPointer() ? /* ended_by() */ 4 : /* end */ 5;
5192+
}
5193+
5194+
if (S.getLangOpts().BoundsSafety) {
5195+
S.Diag(Init->getExprLoc(), diag::err_bounds_safety_auto_dynamic_bound)
5196+
<< Kind << (int)AT->getKeyword();
5197+
return false;
5198+
}
5199+
5200+
// Drop the sugar and emit a warning.
5201+
S.Diag(Init->getExprLoc(), diag::warn_bounds_safety_auto_dynamic_bound)
5202+
<< Kind << (int)AT->getKeyword();
5203+
Result = DesugaredTy;
5204+
return true;
5205+
}
5206+
// TO_UPSTREAM(BoundsSafety) OFF
5207+
51705208
TemplateDeductionResult
51715209
Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
51725210
TemplateDeductionInfo &Info, bool DependentDeduction,
@@ -5247,6 +5285,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
52475285

52485286
DeducedType = getDecltypeForExpr(Init);
52495287
assert(!DeducedType.isNull());
5288+
5289+
// TO_UPSTREAM(BoundsSafety) ON
5290+
if (!CheckAutoCanInferTypeFromBoundsAttributed(*this, AT, Init,
5291+
DeducedType))
5292+
return DeductionFailed(TemplateDeductionResult::AlreadyDiagnosed);
5293+
// TO_UPSTREAM(BoundsSafety) OFF
52505294
} else {
52515295
LocalInstantiationScope InstScope(*this);
52525296

@@ -5311,28 +5355,17 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53115355
return DeductionFailed(TDK);
53125356
}
53135357

5314-
/* TO_UPSTREAM(BoundsSafety) ON*/
5315-
if (getLangOpts().BoundsSafetyAttributes &&
5316-
Init->getType()->isBoundsAttributedType()) {
5317-
unsigned ErrIdx;
5318-
QualType Ty = Init->getType();
5319-
if (auto *DCPTy = Ty->getAs<CountAttributedType>()) {
5320-
ErrIdx = DCPTy->getKind();
5321-
} else {
5322-
auto *DRPTy = Ty->getAs<DynamicRangePointerType>();
5323-
assert(DRPTy);
5324-
ErrIdx = DRPTy->getEndPointer() ? 4 : 5;
5325-
}
5326-
Diag(Loc, diag::err_bounds_safety_auto_dynamic_bound) << ErrIdx;
5327-
return DeductionFailed(TemplateDeductionResult::AlreadyDiagnosed);
5328-
}
5329-
/* TO_UPSTREAM(BoundsSafety) OFF*/
5330-
53315358
// Could be null if somehow 'auto' appears in a non-deduced context.
53325359
if (Deduced[0].getKind() != TemplateArgument::Type)
53335360
return DeductionFailed(TemplateDeductionResult::Incomplete);
53345361
DeducedType = Deduced[0].getAsType();
53355362

5363+
// TO_UPSTREAM(BoundsSafety) ON
5364+
if (!CheckAutoCanInferTypeFromBoundsAttributed(*this, AT, Init,
5365+
DeducedType))
5366+
return DeductionFailed(TemplateDeductionResult::AlreadyDiagnosed);
5367+
// TO_UPSTREAM(BoundsSafety) OFF
5368+
53365369
if (InitList) {
53375370
DeducedType = BuildStdInitializerList(DeducedType, Loc);
53385371
if (DeducedType.isNull())
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// RUN: %clang_cc1 -fsyntax-only -fexperimental-bounds-safety-attributes -x c -ast-dump %s 2>&1 | FileCheck --check-prefix=C %s
2+
// RUN: %clang_cc1 -fsyntax-only -fexperimental-bounds-safety-attributes -x c++ -ast-dump %s 2>&1 | FileCheck --check-prefixes=C,CXX %s
3+
// RUN: %clang_cc1 -fsyntax-only -fexperimental-bounds-safety-attributes -x objective-c -ast-dump %s 2>&1 | FileCheck --check-prefix=C %s
4+
// RUN: %clang_cc1 -fsyntax-only -fexperimental-bounds-safety-attributes -x objective-c++ -ast-dump %s 2>&1 | FileCheck --check-prefixes=C,CXX %s
5+
6+
#include <ptrcheck.h>
7+
8+
// Check that we drop the sugar.
9+
10+
// C: FunctionDecl {{.+}} foo 'void (int * __counted_by(len), int)'
11+
// C-NEXT: |-ParmVarDecl {{.+}} used ptr 'int * __counted_by(len)':'int *'
12+
// C-NEXT: |-ParmVarDecl {{.+}} used len 'int'
13+
// C-NEXT: | `-DependerDeclsAttr {{.+}} <<invalid sloc>> Implicit {{.+}} 0
14+
void foo(int *__counted_by(len) ptr, int len) {
15+
// C: VarDecl {{.+}} p 'int *' cinit
16+
__auto_type p = ptr;
17+
18+
#ifdef __cplusplus
19+
// CXX: VarDecl {{.+}} q 'int *' cinit
20+
auto q = ptr;
21+
22+
// CXX: VarDecl {{.+}} r 'int *' cinit
23+
decltype(auto) r = ptr;
24+
#endif
25+
}
26+
27+
#ifdef __cplusplus
28+
template<typename T>
29+
struct cxx_dep {
30+
int len;
31+
T __counted_by(len) ptr;
32+
33+
void f() {
34+
__auto_type p = ptr;
35+
auto q = ptr;
36+
decltype(auto) r = ptr;
37+
}
38+
};
39+
40+
// CXX: ClassTemplateSpecializationDecl {{.+}} struct cxx_dep
41+
// CXX: VarDecl {{.+}} p 'int *' cinit
42+
// CXX: VarDecl {{.+}} q 'int *' cinit
43+
// CXX: VarDecl {{.+}} r 'int *' cinit
44+
template struct cxx_dep<int *>;
45+
#endif
46+
47+
// C: FunctionDecl {{.+}} bar 'void (int * __counted_by(42))'
48+
// C-NEXT: |-ParmVarDecl {{.+}} used ptr 'int * __counted_by(42)':'int *'
49+
void bar(int *__counted_by(42) ptr) {
50+
// C: VarDecl {{.+}} p 'int *' cinit
51+
__auto_type p = ptr;
52+
53+
#ifdef __cplusplus
54+
// CXX: VarDecl {{.+}} q 'int *' cinit
55+
auto q = ptr;
56+
57+
// CXX: VarDecl {{.+}} r 'int *' cinit
58+
decltype(auto) r = ptr;
59+
#endif
60+
}
61+
62+
// C: FunctionDecl {{.+}} used get_magic_bytes 'void * __sized_by(5)({{.*}})'
63+
void *__sized_by(5) get_magic_bytes(void);
64+
65+
void baz(void) {
66+
// C: VarDecl {{.+}} p 'void *' cinit
67+
__auto_type p = get_magic_bytes();
68+
69+
#ifdef __cplusplus
70+
// CXX: VarDecl {{.+}} q 'void *' cinit
71+
auto q = get_magic_bytes();
72+
73+
// CXX: VarDecl {{.+}} r 'void *' cinit
74+
decltype(auto) r = get_magic_bytes();
75+
#endif
76+
}
77+
78+
#ifdef __cplusplus
79+
template<typename T>
80+
struct cxx_const {
81+
T __counted_by(7) ptr;
82+
83+
void f() {
84+
__auto_type p = ptr;
85+
auto q = ptr;
86+
decltype(auto) r = ptr;
87+
}
88+
};
89+
90+
// CXX: ClassTemplateSpecializationDecl {{.+}} struct cxx_const
91+
// CXX: VarDecl {{.+}} p 'int *' cinit
92+
// CXX: VarDecl {{.+}} q 'int *' cinit
93+
// CXX: VarDecl {{.+}} r 'int *' cinit
94+
template struct cxx_const<int *>;
95+
96+
template<typename T, int len>
97+
struct cxx_const2 {
98+
T __counted_by(len) ptr;
99+
100+
void f() {
101+
__auto_type p = ptr;
102+
auto q = ptr;
103+
decltype(auto) r = ptr;
104+
}
105+
};
106+
107+
// CXX: ClassTemplateSpecializationDecl {{.+}} struct cxx_const2
108+
// CXX: VarDecl {{.+}} p 'int *' cinit
109+
// CXX: VarDecl {{.+}} q 'int *' cinit
110+
// CXX: VarDecl {{.+}} r 'int *' cinit
111+
template struct cxx_const2<int *, 123>;
112+
113+
// CXX: ClassTemplateSpecializationDecl {{.+}} struct cxx_const2
114+
// CXX: VarDecl {{.+}} p 'unsigned int *' cinit
115+
// CXX: VarDecl {{.+}} q 'unsigned int *' cinit
116+
// CXX: VarDecl {{.+}} r 'unsigned int *' cinit
117+
template struct cxx_const2<unsigned *, 99>;
118+
#endif
Lines changed: 109 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,114 @@
1+
// RUN: %clang_cc1 -fbounds-safety -verify=bs %s
2+
// RUN: %clang_cc1 -fbounds-safety -x objective-c -fexperimental-bounds-safety-objc -verify=bs %s
3+
// RUN: %clang_cc1 -fexperimental-bounds-safety-attributes -x c -verify=bsa %s
4+
// RUN: %clang_cc1 -fexperimental-bounds-safety-attributes -x c++ -verify=bsa,bsa-cxx %s
5+
// RUN: %clang_cc1 -fexperimental-bounds-safety-attributes -x objective-c -verify=bsa %s
6+
// RUN: %clang_cc1 -fexperimental-bounds-safety-attributes -x objective-c++ -verify=bsa,bsa-cxx %s
17

8+
#include <ptrcheck.h>
29

3-
// RUN: %clang_cc1 -fbounds-safety -verify %s
4-
// RUN: %clang_cc1 -fbounds-safety -x objective-c -fexperimental-bounds-safety-objc -verify %s
5-
// RUN: %clang_cc1 -fexperimental-bounds-safety-attributes -x c -verify %s
6-
// RUN: %clang_cc1 -fexperimental-bounds-safety-attributes -x c++ -verify %s
7-
// RUN: %clang_cc1 -fexperimental-bounds-safety-attributes -x objective-c -verify %s
8-
// RUN: %clang_cc1 -fexperimental-bounds-safety-attributes -x objective-c++ -verify %s
10+
void cb(int *__counted_by(len) ptr, int len) {
11+
// bs-error@+2{{passing '__counted_by' pointer as '__auto_type' initializer is not yet supported}}
12+
// bsa-warning@+1{{passing '__counted_by' pointer as '__auto_type' initializer is not yet supported}}
13+
__auto_type p = ptr;
914

10-
#include <ptrcheck.h>
15+
#ifdef __cplusplus
16+
// bsa-cxx-warning@+1{{passing '__counted_by' pointer as 'auto' initializer is not yet supported}}
17+
auto q = ptr;
18+
19+
// bsa-cxx-warning@+1{{passing '__counted_by' pointer as 'decltype(auto)' initializer is not yet supported}}
20+
decltype(auto) r = ptr;
21+
#endif
22+
}
23+
24+
void cbn(int *__counted_by_or_null(len) ptr, int len) {
25+
// bs-error@+2{{passing '__counted_by_or_null' pointer as '__auto_type' initializer is not yet supported}}
26+
// bsa-warning@+1{{passing '__counted_by_or_null' pointer as '__auto_type' initializer is not yet supported}}
27+
__auto_type p = ptr;
28+
29+
#ifdef __cplusplus
30+
// bsa-cxx-warning@+1{{passing '__counted_by_or_null' pointer as 'auto' initializer is not yet supported}}
31+
auto q = ptr;
32+
33+
// bsa-cxx-warning@+1{{passing '__counted_by_or_null' pointer as 'decltype(auto)' initializer is not yet supported}}
34+
decltype(auto) r = ptr;
35+
#endif
36+
}
37+
38+
void sb(void *__sized_by(size) ptr, int size) {
39+
// bs-error@+2{{passing '__sized_by' pointer as '__auto_type' initializer is not yet supported}}
40+
// bsa-warning@+1{{passing '__sized_by' pointer as '__auto_type' initializer is not yet supported}}
41+
__auto_type p = ptr;
42+
43+
#ifdef __cplusplus
44+
// bsa-cxx-warning@+1{{passing '__sized_by' pointer as 'auto' initializer is not yet supported}}
45+
auto q = ptr;
46+
47+
// bsa-cxx-warning@+1{{passing '__sized_by' pointer as 'decltype(auto)' initializer is not yet supported}}
48+
decltype(auto) r = ptr;
49+
#endif
50+
}
51+
52+
void eb(void *__ended_by(e) ptr, void *e) {
53+
// bs-error@+2{{passing '__ended_by' pointer as '__auto_type' initializer is not yet supported}}
54+
// bsa-warning@+1{{passing '__ended_by' pointer as '__auto_type' initializer is not yet supported}}
55+
__auto_type p = ptr;
56+
57+
#ifdef __cplusplus
58+
// bsa-cxx-warning@+1{{passing '__ended_by' pointer as 'auto' initializer is not yet supported}}
59+
auto q = ptr;
1160

12-
void foo(int *__counted_by(len) ptr, int len) {
13-
__auto_type p = ptr; // expected-error{{passing '__counted_by' pointer as __auto_type initializer is not yet supported}}
61+
// bsa-cxx-warning@+1{{passing '__ended_by' pointer as 'decltype(auto)' initializer is not yet supported}}
62+
decltype(auto) r = ptr;
63+
#endif
1464
}
65+
66+
void eb_end(void *__ended_by(e) ptr, void *e) {
67+
// bs-error@+2{{passing end pointer as '__auto_type' initializer is not yet supported}}
68+
// bsa-warning@+1{{passing end pointer as '__auto_type' initializer is not yet supported}}
69+
__auto_type p = e;
70+
71+
#ifdef __cplusplus
72+
// bsa-cxx-warning@+1{{passing end pointer as 'auto' initializer is not yet supported}}
73+
auto q = e;
74+
75+
// bsa-cxx-warning@+1{{passing end pointer as 'decltype(auto)' initializer is not yet supported}}
76+
decltype(auto) r = e;
77+
#endif
78+
}
79+
80+
void cb_const(int *__counted_by(42) ptr) {
81+
// bs-error@+2{{passing '__counted_by' pointer as '__auto_type' initializer is not yet supported}}
82+
// bsa-warning@+1{{passing '__counted_by' pointer as '__auto_type' initializer is not yet supported}}
83+
__auto_type p = ptr;
84+
85+
#ifdef __cplusplus
86+
// bsa-cxx-warning@+1{{passing '__counted_by' pointer as 'auto' initializer is not yet supported}}
87+
auto q = ptr;
88+
89+
// bsa-cxx-warning@+1{{passing '__counted_by' pointer as 'decltype(auto)' initializer is not yet supported}}
90+
decltype(auto) r = ptr;
91+
#endif
92+
}
93+
94+
#ifdef __cplusplus
95+
template<typename T>
96+
struct cxx_dep {
97+
int len;
98+
T __counted_by(len) ptr;
99+
100+
void f() {
101+
// bsa-cxx-warning@+1{{passing '__counted_by' pointer as '__auto_type' initializer is not yet supported}}
102+
__auto_type p = ptr;
103+
104+
// bsa-cxx-warning@+1{{passing '__counted_by' pointer as 'auto' initializer is not yet supported}}
105+
auto q = ptr;
106+
107+
// bsa-cxx-warning@+1{{passing '__counted_by' pointer as 'decltype(auto)' initializer is not yet supported}}
108+
decltype(auto) r = ptr;
109+
}
110+
};
111+
112+
// bsa-cxx-note@+1{{in instantiation of member function 'cxx_dep<int *>::f' requested here}}
113+
template struct cxx_dep<int *>;
114+
#endif

0 commit comments

Comments
 (0)