Skip to content

Commit 63cf100

Browse files
authored
Respect signedness for integer literals (#446)
1 parent 28b0282 commit 63cf100

8 files changed

Lines changed: 110 additions & 2 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,7 +2252,9 @@ static std::string getTypedLiteral(const char *num, std::string_view type) {
22522252
std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
22532253
bool incl_type,
22542254
const clang::QualType *type) {
2255-
auto num_as_string = GetNumAsString(expr->getValue());
2255+
auto value = GetIntegerLiteralValue(ctx_, expr, type, CharRustTypeIsSigned());
2256+
llvm::SmallString<16> num_as_string;
2257+
value.toString(num_as_string, 10);
22562258
if (num_as_string[0] != '-' && !incl_type) {
22572259
if (type && (*type)->isFloatingType() &&
22582260
num_as_string.find('.') == llvm::StringRef::npos) {
@@ -2265,7 +2267,7 @@ std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
22652267
auto type_as_string = GetUnsafeTypeAsString(ty);
22662268

22672269
if (ty->isFloatingType() || incl_type) {
2268-
if (expr->getValue().isZero()) {
2270+
if (value.isZero()) {
22692271
if (auto init = Mapper::MapInitializer(ctx_, ty); !init.empty()) {
22702272
return init;
22712273
}
@@ -2956,6 +2958,15 @@ bool Converter::VisitUnaryOperator(clang::UnaryOperator *expr) {
29562958
computed_expr_type_ = ComputedExprType::FreshValue;
29572959
break;
29582960
}
2961+
if (expr->getType()->isUnsignedIntegerType()) {
2962+
{
2963+
PushParen paren(*this);
2964+
Convert(sub_expr);
2965+
}
2966+
StrCat(".wrapping_neg()");
2967+
SetFreshType(expr->getType());
2968+
break;
2969+
}
29592970
[[fallthrough]];
29602971
default:
29612972
StrCat(expr->getOpcodeStr(opcode));

‎cpp2rust/converter/converter.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,12 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
129129

130130
virtual bool EmitsReprCForRecords() const { return true; }
131131

132+
// CharRustType and CharRustTypeIsSigned should disappear after
133+
// https://github.com/Cpp2Rust/cpp2rust/issues/246
132134
virtual const char *CharRustType() const { return "libc::c_char"; }
133135

136+
virtual bool CharRustTypeIsSigned() const { return true; }
137+
134138
virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *decl);
135139

136140
virtual bool ShouldConvertMethod(const clang::CXXMethodDecl *decl);

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,24 @@ bool RefersToUserDefinedDecl(const clang::Expr *expr) {
246246
return decl && IsUserDefinedDecl(decl);
247247
}
248248

249+
llvm::APSInt GetIntegerLiteralValue(const clang::ASTContext &ctx,
250+
const clang::IntegerLiteral *expr,
251+
const clang::QualType *type,
252+
bool char_is_signed) {
253+
auto value = expr->getValue();
254+
bool is_signed = false;
255+
if (type && (*type)->isBuiltinType() && (*type)->isIntegerType() &&
256+
!(*type)->isBooleanType()) {
257+
value = value.zextOrTrunc(ctx.getIntWidth(*type));
258+
is_signed =
259+
(*type)->isSpecificBuiltinType(clang::BuiltinType::Char_S) ||
260+
(*type)->isSpecificBuiltinType(clang::BuiltinType::Char_U)
261+
? char_is_signed
262+
: (*type)->isSignedIntegerType();
263+
}
264+
return llvm::APSInt(value, !is_signed);
265+
}
266+
249267
bool IsUnsignedArithOp(const clang::BinaryOperator *expr) {
250268
clang::QualType lhs_type;
251269
clang::QualType rhs_type;

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <clang/AST/Expr.h>
1010
#include <clang/AST/StmtCXX.h>
1111
#include <clang/AST/Type.h>
12+
#include <llvm/ADT/APSInt.h>
1213
#include <llvm/ADT/STLFunctionalExtras.h>
1314

1415
#include <optional>
@@ -65,6 +66,11 @@ bool RefersToUserDefinedDecl(const clang::Expr *expr);
6566

6667
bool IsUnsignedArithOp(const clang::BinaryOperator *expr);
6768

69+
llvm::APSInt GetIntegerLiteralValue(const clang::ASTContext &ctx,
70+
const clang::IntegerLiteral *expr,
71+
const clang::QualType *type,
72+
bool char_is_signed);
73+
6874
bool IsMut(clang::QualType qual_type);
6975

7076
bool RustSizeDivergesFromC(clang::QualType qt);

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class ConverterRefCount final : public Converter {
3737
bool EmitsReprCForRecords() const override { return false; }
3838

3939
const char *CharRustType() const override { return "u8"; }
40+
bool CharRustTypeIsSigned() const override { return false; }
4041

4142
std::string GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
4243
std::string_view value) override;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
pub fn main() {
10+
__cpp2rust_init_globals();
11+
std::process::exit(main_0());
12+
}
13+
fn main_0() -> i32 {
14+
let x1: Value<i32> = Rc::new(RefCell::new(-1_i32));
15+
assert!(((((*x1.borrow()) == -1_i32) as i32) != 0));
16+
let x2: Value<i8> = Rc::new(RefCell::new(-1_i8));
17+
assert!((((((*x2.borrow()) as i32) == -1_i32) as i32) != 0));
18+
let u1: Value<u32> = Rc::new(RefCell::new(5_u32));
19+
let u2: Value<u32> = Rc::new(RefCell::new((*u1.borrow()).wrapping_neg()));
20+
assert!(((((*u2.borrow()) == 4294967291_u32) as i32) != 0));
21+
let c1: Value<u8> = Rc::new(RefCell::new(255_u8));
22+
assert!(((((((*c1.borrow()) as u8) as i32) == 255) as i32) != 0));
23+
return 0;
24+
}
25+
pub fn __cpp2rust_init_globals() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
pub fn main() {
10+
unsafe {
11+
__cpp2rust_init_globals();
12+
std::process::exit(main_0() as i32);
13+
}
14+
}
15+
unsafe fn main_0() -> i32 {
16+
let mut x1: i32 = -1_i32;
17+
assert!(((((x1) == (-1_i32)) as i32) != 0));
18+
let mut x2: i8 = -1_i8;
19+
assert!(((((x2 as i32) == (-1_i32)) as i32) != 0));
20+
let mut u1: u32 = 5_u32;
21+
let mut u2: u32 = (u1).wrapping_neg();
22+
assert!(((((u2) == (4294967291_u32)) as i32) != 0));
23+
let mut c1: libc::c_char = (-1 as libc::c_char);
24+
assert!((((((c1 as u8) as i32) == (255)) as i32) != 0));
25+
return 0;
26+
}
27+
pub unsafe fn __cpp2rust_init_globals() {}

‎tests/unit/signed_integer.c‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <assert.h>
2+
3+
int main() {
4+
int x1 = 0xFFFFFFFF;
5+
assert(x1 == -1);
6+
signed char x2 = 0xFF;
7+
assert(x2 == -1);
8+
9+
unsigned int u1 = 5;
10+
unsigned int u2 = -u1;
11+
assert(u2 == 4294967291u);
12+
13+
char c1 = 0xFF;
14+
assert((unsigned char)c1 == 0xFF);
15+
return 0;
16+
}

0 commit comments

Comments
 (0)