-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
llvm/llvm-project#62248 Reviewed By: yabinc, aaron.ballman, #clang-language-wg Differential Revision: https://reviews.llvm.org/D157331
- Loading branch information
1 parent
81d0470
commit 3694697
Showing
12 changed files
with
273 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/*===---- stdckdint.h - Standard header for checking integer----------------=== | ||
* | ||
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
* See https://llvm.org/LICENSE.txt for license information. | ||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
* | ||
*===-----------------------------------------------------------------------=== | ||
*/ | ||
|
||
#ifndef __STDCKDINT_H | ||
#define __STDCKDINT_H | ||
|
||
/* If we're hosted, fall back to the system's stdckdint.h. FreeBSD, for | ||
* example, already has a Clang-compatible stdckdint.h header. | ||
* | ||
* The `stdckdint.h` header requires C 23 or newer. | ||
*/ | ||
#if __STDC_HOSTED__ && __has_include_next(<stdckdint.h>) | ||
#include_next <stdckdint.h> | ||
#else | ||
|
||
/* C23 7.20.1 Defines several macros for performing checked integer arithmetic*/ | ||
|
||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L | ||
#define __STDC_VERSION_STDCKDINT_H__ 202311L | ||
|
||
// Both A and B shall be any integer type other than "plain" char, bool, a bit- | ||
// precise integer type, or an enumerated type, and they need not be the same. | ||
|
||
// R shall be a modifiable lvalue of any integer type other than "plain" char, | ||
// bool, a bit-precise integer type, or an enumerated type. It shouldn't be | ||
// short type, either. Otherwise, it may be unable to hold two the result of | ||
// operating two 'int's. | ||
|
||
// A diagnostic message will be produced if A or B are not suitable integer | ||
// types, or if R is not a modifiable lvalue of a suitable integer type or R | ||
// is short type. | ||
#define ckd_add(R, A, B) __builtin_add_overflow((A), (B), (R)) | ||
#define ckd_sub(R, A, B) __builtin_sub_overflow((A), (B), (R)) | ||
#define ckd_mul(R, A, B) __builtin_mul_overflow((A), (B), (R)) | ||
#endif | ||
|
||
#endif /* __STDC_HOSTED__ */ | ||
#endif /* __STDCKDINT_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3 | ||
// RUN: %clang_cc1 -triple=x86_64 -verify -ffreestanding -std=c23 %s | ||
|
||
/* WG14 N2683: Clang 18 | ||
* Towards Integer Safety | ||
*/ | ||
#include <stdckdint.h> | ||
#include <stddef.h> | ||
#include <stdint.h> | ||
|
||
void test_semantic() { | ||
int64_t result64 = 0; | ||
int32_t result32 = 0; | ||
wchar_t wide_char = L'A'; // The ascii value of `A` is 65 | ||
|
||
bool flag_add = ckd_add(&result64, INT32_MAX, 1); | ||
bool flag_sub = ckd_sub(&result32, INT32_MAX, -1); | ||
bool flag_mul = ckd_mul(&result64, INT64_MAX, 1); | ||
|
||
bool flag = ckd_add(&result64, wide_char, result32); // In C, wchar_t is a typedef to some integer type and is allowed. | ||
|
||
// FIXME: add static_assert calls to check the resulting values for correctness | ||
// once the constant expression interpreter is able to handle the checked arithmetic | ||
// builtins in C. Currently, they're only a valid constant expression in C++ due to | ||
// looking for an ICE in C. Also all values in the tests of n2683_2.c should be checked. | ||
} | ||
|
||
void test_invalid_input() { | ||
_BitInt(33) a33 = 1; | ||
char char_var = 'd'; // The ascii value of `d` is 100 | ||
bool bool_var = 1; | ||
const int const_result = 0; | ||
enum week{Mon, Tue, Wed}; | ||
enum week day = Mon; | ||
int a = 100; | ||
int b = 55; | ||
int result = 10; | ||
char plain_char[] = {U'牛'}; /* expected-warning {{implicit conversion from 'unsigned int' to 'char' changes value from 29275 to 91}} */ | ||
|
||
// invalid operand argument | ||
bool flag_no_bitint = ckd_add(&result, a33, a); /* expected-error {{operand argument to checked integer operation must be an integer type other than plain 'char', 'bool', bit-precise, or an enumeration ('_BitInt(33)' invalid)}} */ | ||
bool flag_no_bool = ckd_sub(&result, bool_var, b); /* expected-error {{operand argument to checked integer operation must be an integer type other than plain 'char', 'bool', bit-precise, or an enumeration ('bool' invalid)}} */ | ||
bool flag_no_char = ckd_mul(&result, char_var, a); /* expected-error {{operand argument to checked integer operation must be an integer type other than plain 'char', 'bool', bit-precise, or an enumeration ('char' invalid)}} */ | ||
bool flag_no_enum = ckd_mul(&result, day, b); /* expected-error {{operand argument to checked integer operation must be an integer type other than plain 'char', 'bool', bit-precise, or an enumeration ('enum week' invalid)}} */ | ||
|
||
// invalid result type | ||
bool flag_nostr = ckd_sub(&plain_char, a, b); /* expected-error {{result argument to checked integer operation must be a pointer to a non-const integer type other than plain 'char', 'bool', bit-precise, or an enumeration ('char (*)[1]' invalid)}} */ | ||
bool flag_nobool = ckd_mul(&bool_var, a, b); /* expected-error {{result argument to checked integer operation must be a pointer to a non-const integer type other than plain 'char', 'bool', bit-precise, or an enumeration ('bool *' invalid)}} */ | ||
bool flag_noptr = ckd_add(result, a, b); /* expected-error {{result argument to checked integer operation must be a pointer to a non-const integer type other than plain 'char', 'bool', bit-precise, or an enumeration ('int' invalid)}} */ | ||
bool flag_noconst = ckd_sub(&const_result, a, b); /* expected-error {{result argument to checked integer operation must be a pointer to a non-const integer type other than plain 'char', 'bool', bit-precise, or an enumeration ('const int *' invalid)}} */ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3 | ||
// RUN: %clang_cc1 -triple=x86_64 -emit-llvm -o - -std=c23 %s | FileCheck %s | ||
|
||
#include <stdckdint.h> | ||
#include <stdint.h> | ||
|
||
// CHECK-LABEL: define dso_local void @test_add_overflow_to64( | ||
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RESULT64:%.*]] = alloca i64, align 8 | ||
// CHECK-NEXT: [[FLAG_ADD:%.*]] = alloca i8, align 1 | ||
// CHECK-NEXT: store i64 0, ptr [[RESULT64]], align 8 | ||
// CHECK-NEXT: [[TMP0:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 2147483647, i64 1) | ||
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1 | ||
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i64, i1 } [[TMP0]], 0 | ||
// CHECK-NEXT: store i64 [[TMP2]], ptr [[RESULT64]], align 8 | ||
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP1]] to i8 | ||
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[FLAG_ADD]], align 1 | ||
// CHECK-NEXT: ret void | ||
// | ||
void test_add_overflow_to64() { | ||
int64_t result64 = 0; | ||
bool flag_add = ckd_add(&result64, INT32_MAX, 1); | ||
} | ||
|
||
// CHECK-LABEL: define dso_local void @test_sub_overflow( | ||
// CHECK-SAME: ) #[[ATTR0]] { | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RESULT32:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[FLAG_SUB:%.*]] = alloca i8, align 1 | ||
// CHECK-NEXT: store i32 0, ptr [[RESULT32]], align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 2147483647, i32 -1) | ||
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1 | ||
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 | ||
// CHECK-NEXT: store i32 [[TMP2]], ptr [[RESULT32]], align 4 | ||
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP1]] to i8 | ||
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[FLAG_SUB]], align 1 | ||
// CHECK-NEXT: ret void | ||
// | ||
void test_sub_overflow() { | ||
int32_t result32 = 0; | ||
bool flag_sub = ckd_sub(&result32, INT32_MAX, -1); | ||
} | ||
|
||
// CHECK-LABEL: define dso_local void @test_mul_normal( | ||
// CHECK-SAME: ) #[[ATTR0]] { | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[FLAG_MUL:%.*]] = alloca i8, align 1 | ||
// CHECK-NEXT: store i32 3, ptr [[A]], align 4 | ||
// CHECK-NEXT: store i32 0, ptr [[RESULT]], align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 4 | ||
// CHECK-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP0]], i32 2) | ||
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 | ||
// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 | ||
// CHECK-NEXT: store i32 [[TMP3]], ptr [[RESULT]], align 4 | ||
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP2]] to i8 | ||
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[FLAG_MUL]], align 1 | ||
// CHECK-NEXT: ret void | ||
// | ||
void test_mul_normal() { | ||
int a = 3; | ||
int result = 0; | ||
bool flag_mul = ckd_mul(&result, a, 2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3 | ||
// RUN: %clang_cc1 -triple=x86_64 -emit-llvm -verify -std=c23 %s -o - | FileCheck %s | ||
|
||
// expected-no-diagnostics | ||
|
||
#include <stdckdint.h> | ||
|
||
_Static_assert(__STDC_VERSION_STDCKDINT_H__ == 202311L, ""); | ||
|
||
// CHECK-LABEL: define dso_local zeroext i1 @test_ckd_add( | ||
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 -1073741826, i32 -1073741826) | ||
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1 | ||
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 | ||
// CHECK-NEXT: store i32 [[TMP2]], ptr [[RESULT]], align 4 | ||
// CHECK-NEXT: ret i1 [[TMP1]] | ||
// | ||
bool test_ckd_add() { | ||
int result; | ||
return ckd_add(&result, -1073741826, -1073741826); | ||
} | ||
|
||
// CHECK-LABEL: define dso_local zeroext i1 @test_ckd_sub( | ||
// CHECK-SAME: ) #[[ATTR0]] { | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 -1073741826, i32 1073741826) | ||
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1 | ||
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 | ||
// CHECK-NEXT: store i32 [[TMP2]], ptr [[RESULT]], align 4 | ||
// CHECK-NEXT: ret i1 [[TMP1]] | ||
// | ||
bool test_ckd_sub() { | ||
int result; | ||
return ckd_sub(&result, -1073741826, 1073741826); | ||
} | ||
|
||
// CHECK-LABEL: define dso_local zeroext i1 @test_ckd_mul( | ||
// CHECK-SAME: ) #[[ATTR0]] { | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 -1073741826, i32 2) | ||
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1 | ||
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 | ||
// CHECK-NEXT: store i32 [[TMP2]], ptr [[RESULT]], align 4 | ||
// CHECK-NEXT: ret i1 [[TMP1]] | ||
// | ||
bool test_ckd_mul() { | ||
int result; | ||
return ckd_mul(&result, -1073741826, 2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters