Skip to content

Commit 7174224

Browse files
committed
[Clang] Add __datasizeof
1 parent cc9ad72 commit 7174224

File tree

11 files changed

+150
-19
lines changed

11 files changed

+150
-19
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,18 @@ Builtin Macros
424424
"UTF-16" or "UTF-32" (but may change in the future if the
425425
``-fwide-exec-charset="Encoding-Name"`` option is implemented.)
426426

427+
Implementation-defined keywords
428+
===============================
429+
430+
__datasizeof
431+
------------
432+
433+
``__datasizeof`` behaves like ``sizeof``, except that it returns the size of the
434+
type ignoring tail padding.
435+
436+
..
437+
FIXME: This should list all the keyword extensions
438+
427439
.. _langext-vectors:
428440

429441
Vectors and Extended Vectors

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ Non-comprehensive list of changes in this release
217217
(e.g., ``uint16x8_t``), this returns the constant number of elements at compile-time.
218218
For scalable vectors, e.g., SVE or RISC-V V, the number of elements is not known at compile-time and is
219219
determined at runtime.
220+
* The ``__datasizeof`` keyword has been added. It is similar to ``sizeof``
221+
except that it returns the size of a type ignoring tail padding.
220222

221223
New Compiler Flags
222224
------------------

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ EXTENSION(gnu_asm_goto_with_outputs_full, LangOpts.GNUAsm)
277277
EXTENSION(matrix_types, LangOpts.MatrixTypes)
278278
EXTENSION(matrix_types_scalar_division, true)
279279
EXTENSION(cxx_attributes_on_using_declarations, LangOpts.CPlusPlus11)
280+
EXTENSION(datasizeof, LangOpts.CPlusPlus)
280281

281282
FEATURE(builtin_headers_in_system_modules, LangOpts.BuiltinHeadersInSystemModules)
282283
FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVTables)

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ KEYWORD(return , KEYALL)
310310
KEYWORD(short , KEYALL)
311311
KEYWORD(signed , KEYALL)
312312
UNARY_EXPR_OR_TYPE_TRAIT(sizeof, SizeOf, KEYALL)
313+
UNARY_EXPR_OR_TYPE_TRAIT(__datasizeof, DataSizeOf, KEYCXX)
313314
KEYWORD(static , KEYALL)
314315
KEYWORD(struct , KEYALL)
315316
KEYWORD(switch , KEYALL)

clang/lib/AST/ExprConstant.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3184,9 +3184,14 @@ static bool HandleLValueIndirectMember(EvalInfo &Info, const Expr *E,
31843184
return true;
31853185
}
31863186

3187+
enum class SizeOfType {
3188+
SizeOf,
3189+
DataSizeOf,
3190+
};
3191+
31873192
/// Get the size of the given type in char units.
3188-
static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc,
3189-
QualType Type, CharUnits &Size) {
3193+
static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc, QualType Type,
3194+
CharUnits &Size, SizeOfType SOT = SizeOfType::SizeOf) {
31903195
// sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
31913196
// extension.
31923197
if (Type->isVoidType() || Type->isFunctionType()) {
@@ -3206,7 +3211,10 @@ static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc,
32063211
return false;
32073212
}
32083213

3209-
Size = Info.Ctx.getTypeSizeInChars(Type);
3214+
if (SOT == SizeOfType::SizeOf)
3215+
Size = Info.Ctx.getTypeSizeInChars(Type);
3216+
else
3217+
Size = Info.Ctx.getTypeInfoDataSizeInChars(Type).Width;
32103218
return true;
32113219
}
32123220

@@ -13689,6 +13697,7 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
1368913697
return Success(1, E);
1369013698
}
1369113699

13700+
case UETT_DataSizeOf:
1369213701
case UETT_SizeOf: {
1369313702
QualType SrcTy = E->getTypeOfArgument();
1369413703
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
@@ -13697,8 +13706,11 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
1369713706
SrcTy = Ref->getPointeeType();
1369813707

1369913708
CharUnits Sizeof;
13700-
if (!HandleSizeof(Info, E->getExprLoc(), SrcTy, Sizeof))
13709+
if (!HandleSizeof(Info, E->getExprLoc(), SrcTy, Sizeof,
13710+
E->getKind() == UETT_DataSizeOf ? SizeOfType::DataSizeOf
13711+
: SizeOfType::SizeOf)) {
1370113712
return false;
13713+
}
1370213714
return Success(Sizeof, E);
1370313715
}
1370413716
case UETT_OpenMPRequiredSimdAlign:

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "clang/AST/Mangle.h"
2929
#include "clang/AST/TypeLoc.h"
3030
#include "clang/Basic/ABI.h"
31+
#include "clang/Basic/DiagnosticAST.h"
3132
#include "clang/Basic/Module.h"
3233
#include "clang/Basic/SourceManager.h"
3334
#include "clang/Basic/TargetInfo.h"
@@ -5068,6 +5069,14 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
50685069
Out << 'a';
50695070
MangleAlignofSizeofArg();
50705071
break;
5072+
case UETT_DataSizeOf: {
5073+
DiagnosticsEngine &Diags = Context.getDiags();
5074+
unsigned DiagID =
5075+
Diags.getCustomDiagID(DiagnosticsEngine::Error,
5076+
"cannot yet mangle __datasizeof expression");
5077+
Diags.Report(DiagID);
5078+
return;
5079+
}
50715080
case UETT_VecStep: {
50725081
DiagnosticsEngine &Diags = Context.getDiags();
50735082
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,9 +3053,10 @@ Value *
30533053
ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
30543054
const UnaryExprOrTypeTraitExpr *E) {
30553055
QualType TypeToSize = E->getTypeOfArgument();
3056-
if (E->getKind() == UETT_SizeOf) {
3056+
if (auto Kind = E->getKind();
3057+
Kind == UETT_SizeOf || Kind == UETT_DataSizeOf) {
30573058
if (const VariableArrayType *VAT =
3058-
CGF.getContext().getAsVariableArrayType(TypeToSize)) {
3059+
CGF.getContext().getAsVariableArrayType(TypeToSize)) {
30593060
if (E->isArgumentType()) {
30603061
// sizeof(type) - make sure to emit the VLA size.
30613062
CGF.EmitVariablyModifiedType(TypeToSize);

clang/lib/Parse/ParseExpr.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
14601460
// unary-expression: '__alignof' '(' type-name ')'
14611461
case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression
14621462
// unary-expression: 'sizeof' '(' type-name ')'
1463+
// unary-expression: '__datasizeof' unary-expression
1464+
// unary-expression: '__datasizeof' '(' type-name ')'
1465+
case tok::kw___datasizeof:
14631466
case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression
14641467
// unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')'
14651468
case tok::kw___builtin_omp_required_simd_align:
@@ -2307,6 +2310,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
23072310
/// unary-expression: [C99 6.5.3]
23082311
/// 'sizeof' unary-expression
23092312
/// 'sizeof' '(' type-name ')'
2313+
/// [Clang] '__datasizeof' unary-expression
2314+
/// [Clang] '__datasizeof' '(' type-name ')'
23102315
/// [GNU] '__alignof' unary-expression
23112316
/// [GNU] '__alignof' '(' type-name ')'
23122317
/// [C11] '_Alignof' '(' type-name ')'
@@ -2335,8 +2340,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
23352340
SourceRange &CastRange) {
23362341

23372342
assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual, tok::kw_sizeof,
2338-
tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof,
2339-
tok::kw_vec_step,
2343+
tok::kw___datasizeof, tok::kw___alignof, tok::kw_alignof,
2344+
tok::kw__Alignof, tok::kw_vec_step,
23402345
tok::kw___builtin_omp_required_simd_align,
23412346
tok::kw___builtin_vectorelements) &&
23422347
"Not a typeof/sizeof/alignof/vec_step expression!");
@@ -2347,8 +2352,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
23472352
if (Tok.isNot(tok::l_paren)) {
23482353
// If construct allows a form without parenthesis, user may forget to put
23492354
// pathenthesis around type name.
2350-
if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof,
2351-
tok::kw__Alignof)) {
2355+
if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___datasizeof, tok::kw___alignof,
2356+
tok::kw_alignof, tok::kw__Alignof)) {
23522357
if (isTypeIdUnambiguously()) {
23532358
DeclSpec DS(AttrFactory);
23542359
ParseSpecifierQualifierList(DS);
@@ -2451,14 +2456,16 @@ ExprResult Parser::ParseSYCLUniqueStableNameExpression() {
24512456
/// 'sizeof' unary-expression
24522457
/// 'sizeof' '(' type-name ')'
24532458
/// [C++11] 'sizeof' '...' '(' identifier ')'
2459+
/// [Clang] '__datasizeof' unary-expression
2460+
/// [Clang] '__datasizeof' '(' type-name ')'
24542461
/// [GNU] '__alignof' unary-expression
24552462
/// [GNU] '__alignof' '(' type-name ')'
24562463
/// [C11] '_Alignof' '(' type-name ')'
24572464
/// [C++11] 'alignof' '(' type-id ')'
24582465
/// \endverbatim
24592466
ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
2460-
assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof,
2461-
tok::kw__Alignof, tok::kw_vec_step,
2467+
assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___datasizeof, tok::kw___alignof,
2468+
tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step,
24622469
tok::kw___builtin_omp_required_simd_align,
24632470
tok::kw___builtin_vectorelements) &&
24642471
"Not a sizeof/alignof/vec_step expression!");
@@ -2531,16 +2538,29 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
25312538
CastRange);
25322539

25332540
UnaryExprOrTypeTrait ExprKind = UETT_SizeOf;
2534-
if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
2541+
switch (OpTok.getKind()) {
2542+
case tok::kw_alignof:
2543+
case tok::kw__Alignof:
25352544
ExprKind = UETT_AlignOf;
2536-
else if (OpTok.is(tok::kw___alignof))
2545+
break;
2546+
case tok::kw___alignof:
25372547
ExprKind = UETT_PreferredAlignOf;
2538-
else if (OpTok.is(tok::kw_vec_step))
2548+
break;
2549+
case tok::kw_vec_step:
25392550
ExprKind = UETT_VecStep;
2540-
else if (OpTok.is(tok::kw___builtin_omp_required_simd_align))
2551+
break;
2552+
case tok::kw___builtin_omp_required_simd_align:
25412553
ExprKind = UETT_OpenMPRequiredSimdAlign;
2542-
else if (OpTok.is(tok::kw___builtin_vectorelements))
2554+
break;
2555+
case tok::kw___datasizeof:
2556+
ExprKind = UETT_DataSizeOf;
2557+
break;
2558+
case tok::kw___builtin_vectorelements:
25432559
ExprKind = UETT_VectorElements;
2560+
break;
2561+
default:
2562+
break;
2563+
}
25442564

25452565
if (isCastExpr)
25462566
return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),

clang/lib/Sema/SemaExpr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4444,8 +4444,9 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
44444444
assert(!ExprTy->isReferenceType());
44454445

44464446
bool IsUnevaluatedOperand =
4447-
(ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf ||
4448-
ExprKind == UETT_PreferredAlignOf || ExprKind == UETT_VecStep);
4447+
(ExprKind == UETT_SizeOf || ExprKind == UETT_DataSizeOf ||
4448+
ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf ||
4449+
ExprKind == UETT_VecStep);
44494450
if (IsUnevaluatedOperand) {
44504451
ExprResult Result = CheckUnevaluatedOperand(E);
44514452
if (Result.isInvalid())

clang/test/CodeGenCXX/datasizeof.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-gnu-linux -emit-llvm %s -o - | FileCheck %s
2+
3+
// CHECK-LABEL: define dso_local noundef i32 @_Z4testi(
4+
// CHECK-SAME: i32 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]] {
5+
// CHECK-NEXT: entry:
6+
// CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
7+
// CHECK-NEXT: store i32 [[I]], ptr [[I_ADDR]], align 4
8+
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
9+
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP0]], 1
10+
// CHECK-NEXT: store i32 [[INC]], ptr [[I_ADDR]], align 4
11+
// CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
12+
// CHECK-NEXT: [[TMP2:%.*]] = mul nuw i64 4, [[TMP1]]
13+
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
14+
// CHECK-NEXT: ret i32 [[TMP3]]
15+
//
16+
int test(int i) {
17+
(void)__datasizeof(int[i++]);
18+
return i;
19+
}

clang/test/SemaCXX/datasizeof.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-linux-gnu -verify %s
2+
3+
#if !__has_extension(datasizeof)
4+
# error "Expected datasizeof extension"
5+
#endif
6+
7+
struct HasPadding {
8+
int i;
9+
char c;
10+
};
11+
12+
struct HasUsablePadding {
13+
int i;
14+
char c;
15+
16+
HasUsablePadding() {}
17+
};
18+
19+
struct Incomplete; // expected-note {{forward declaration of 'Incomplete'}}
20+
21+
static_assert(__datasizeof(int) == 4);
22+
static_assert(__datasizeof(HasPadding) == 8);
23+
static_assert(__datasizeof(HasUsablePadding) == 5);
24+
static_assert(__datasizeof(void)); // expected-error {{invalid application of '__datasizeof' to an incomplete type 'void'}}
25+
static_assert(__datasizeof(Incomplete)); // expected-error {{invalid application of '__datasizeof' to an incomplete type 'Incomplete'}}
26+
27+
static_assert([] {
28+
int* p = nullptr;
29+
HasPadding* p2 = nullptr;
30+
HasUsablePadding* p3 = nullptr;
31+
static_assert(__datasizeof(*p) == 4);
32+
static_assert(__datasizeof *p == 4);
33+
static_assert(__datasizeof(*p2) == 8);
34+
static_assert(__datasizeof(*p3) == 5);
35+
36+
return true;
37+
}());
38+
39+
template <typename Ty>
40+
constexpr int data_size_of() {
41+
return __datasizeof(Ty);
42+
}
43+
static_assert(data_size_of<int>() == __datasizeof(int));
44+
static_assert(data_size_of<HasPadding>() == __datasizeof(HasPadding));
45+
static_assert(data_size_of<HasUsablePadding>() == __datasizeof(HasUsablePadding));
46+
47+
struct S {
48+
int i = __datasizeof(S);
49+
float f;
50+
char c;
51+
};
52+
53+
static_assert(S{}.i == 9);

0 commit comments

Comments
 (0)