Skip to content

Commit 30be662

Browse files
committed
fixup: verify span-like struct/class bases
If present, they must be empty.
1 parent 19adf5b commit 30be662

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3465,6 +3465,8 @@ def note_returned_not_integer_field
34653465
def note_returned_not_wide_enough_field
34663466
: Note<"integer field #%0 of span-like type is not wide enough (minimum "
34673467
"width: %1)">;
3468+
def note_inherits_not_empty_base
3469+
: Note<"returned struct/class inherits from a non-empty base">;
34683470
def warn_attribute_return_pointers_refs_only : Warning<
34693471
"%0 attribute only applies to return values that are pointers or references">,
34703472
InGroup<IgnoredAttributes>;

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,14 @@ bool Sema::CheckSpanLikeType(const AttributeCommonInfo &CI,
18571857
const RecordDecl *RD = Ty->getAsRecordDecl();
18581858
if (!RD || RD->isUnion())
18591859
return emitWarning(diag::note_returned_not_struct);
1860+
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
1861+
for (const auto &Base : CXXRD->bases()) {
1862+
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
1863+
if (!BaseDecl || !BaseDecl->isEmpty()) {
1864+
return emitWarning(diag::note_inherits_not_empty_base);
1865+
}
1866+
}
1867+
}
18601868
auto FieldsBegin = RD->field_begin();
18611869
auto FieldsCount = std::distance(FieldsBegin, RD->field_end());
18621870
if (FieldsCount != 2)

clang/test/SemaCXX/attr-malloc_span.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,26 @@ __attribute((malloc_span)) auto trailing_return_temmplate_good(void) -> Pair<int
108108
__attribute((malloc_span)) auto trailing_return_temmplate_bad(void) -> Pair<int, int> {
109109
return Pair<int, int>{};
110110
}
111+
112+
struct EmptyBase {
113+
};
114+
115+
struct GoodChildSpan : EmptyBase {
116+
void *p;
117+
int n;
118+
};
119+
120+
__attribute((malloc_span)) GoodChildSpan return_span_with_good_base(void); // no-warning
121+
122+
struct NonEmptyBase {
123+
void *other_p;
124+
};
125+
126+
struct BadChildSpan : EmptyBase, NonEmptyBase {
127+
void *p;
128+
int n;
129+
};
130+
131+
// expected-warning@+2 {{attribute only applies to functions that return span-like structures}}
132+
// expected-note@+1 {{returned struct/class inherits from a non-empty base}}
133+
__attribute((malloc_span)) BadChildSpan return_span_with_bad_base(void);

0 commit comments

Comments
 (0)