Skip to content

Commit 42de8c0

Browse files
committed
Get type of integers without ending l or ll
1 parent abe03c4 commit 42de8c0

File tree

4 files changed

+84
-11
lines changed

4 files changed

+84
-11
lines changed

bindgen/defines/DefineFinder.cpp

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <clang/Basic/IdentifierTable.h>
44
#include <clang/Lex/LiteralSupport.h>
55
#include <clang/Lex/MacroInfo.h>
6+
#include <llvm/ADT/APInt.h>
7+
#include <llvm/ADT/APSInt.h>
68

79
DefineFinder::DefineFinder(IR &ir, const clang::CompilerInstance &compiler,
810
clang::Preprocessor &pp)
@@ -76,18 +78,27 @@ void DefineFinder::MacroUndefined(const clang::Token &MacroNameTok,
7678
}
7779

7880
void DefineFinder::addNumericConstantDefine(const std::string &macroName,
79-
const std::string &literal,
81+
std::string literal,
8082
const clang::Token *finalToken) {
8183
clang::NumericLiteralParser parser(literal, finalToken->getLocation(), pp);
8284
std::string type;
8385
if (parser.isIntegerLiteral()) {
86+
std::replace(literal.begin(), literal.end(), 'l', 'L');
8487
if (parser.isLongLong) {
85-
return;
86-
}
87-
if (parser.isLong) {
88+
/* literal has `LL` ending but `long long` is represented as
89+
* `Long` in Scala Native */
90+
literal = literal.substr(0, literal.length() - 1); // remove last L
91+
type = "native.CLongLong";
92+
} else if (parser.isLong) {
93+
/* literal already has `L` ending */
8894
type = "native.CLong";
8995
} else {
90-
type = "native.CInt";
96+
/* literal may not have `l` or `ll` ending but still be of long type
97+
* NumericLiteralParser does not recognize that 10000000000
98+
* is a long value.
99+
* Therefore we need to check that value fits into certain number
100+
* of bits. */
101+
getTypeOfIntLiteralWithoutEnding(parser, literal, type);
91102
}
92103
} else {
93104
if (parser.isFloat) {
@@ -99,3 +110,45 @@ void DefineFinder::addNumericConstantDefine(const std::string &macroName,
99110
ir.addLiteralDefine(macroName, literal, type);
100111
}
101112
}
113+
114+
/**
115+
* Check if literal without `l` or `ll` ending fits into int or long variable.
116+
*
117+
* Set `literal` and `type` parameters.
118+
*/
119+
void DefineFinder::getTypeOfIntLiteralWithoutEnding(
120+
clang::NumericLiteralParser parser, std::string &literal,
121+
std::string &type) {
122+
123+
bool isSigned = llvm::APSInt(literal).isSigned();
124+
125+
llvm::APInt intSignedVal(4 * 8, 0, false);
126+
llvm::APInt intUnsignedVal(4 * 8 - 1, 0, false);
127+
/* it does not matter if APInt instance is signed or not
128+
* because when calling GetIntegerValue it will check if unsigned value may
129+
* fit into the full width defined in APInt */
130+
if ((!isSigned && !parser.GetIntegerValue(intUnsignedVal)) ||
131+
(isSigned && !parser.GetIntegerValue(intSignedVal))) {
132+
type = "native.CInt";
133+
} else {
134+
llvm::APInt longSignedVal(8 * 8, 0, false);
135+
llvm::APInt longUnsignedVal(8 * 8 - 1, 0, false);
136+
if ((!isSigned && !parser.GetIntegerValue(longUnsignedVal)) ||
137+
(isSigned && !parser.GetIntegerValue(longSignedVal))) {
138+
type = "native.CLong";
139+
literal = literal + "L";
140+
} else {
141+
llvm::errs() << "Waring: integer value does not fit into 8 bytes: "
142+
<< literal << "\n";
143+
llvm::errs().flush();
144+
/**
145+
* `long long` value has mostly the same size as `long`.
146+
* Moreover in Scala Native the type is represented as `Long`:
147+
* @code
148+
* type CLongLong = Long
149+
* @endcode
150+
* Therefore the case of `long long` is not considered here.
151+
*/
152+
}
153+
}
154+
}

bindgen/defines/DefineFinder.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "../ir/IR.h"
55
#include <clang/Frontend/CompilerInstance.h>
6+
#include <clang/Lex/LiteralSupport.h>
67
#include <clang/Lex/PPCallbacks.h>
78
#include <clang/Lex/Preprocessor.h>
89

@@ -15,7 +16,7 @@ class DefineFinder : public clang::PPCallbacks {
1516
const clang::MacroDirective *MD) override;
1617

1718
void MacroUndefined(const clang::Token &MacroNameTok,
18-
const clang::MacroDefinition &MD) override;
19+
const clang::MacroDefinition &MD);
1920

2021
private:
2122
IR &ir;
@@ -25,8 +26,12 @@ class DefineFinder : public clang::PPCallbacks {
2526
const clang::Token *getFinalIdentifier(const clang::Token &token) const;
2627

2728
void addNumericConstantDefine(const std::string &macroName,
28-
const std::string &literal,
29+
std::string literal,
2930
const clang::Token *finalToken);
31+
32+
void getTypeOfIntLiteralWithoutEnding(clang::NumericLiteralParser parser,
33+
std::string &literal,
34+
std::string &type);
3035
};
3136

3237
#endif // SCALA_NATIVE_BINDGEN_DEFINEFINDER_H

tests/samples/Define.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
#define STRING "Hello, World!"
22

3-
#define INT 42
4-
// #define LONG 10000000000 // this will fail
3+
#define LONG 1000000000000l
4+
#define LONG_WITHOUT_ENDING 1000000000000
5+
#define LONG_LONG 1000000000000ll
6+
7+
/* maximum unsigned long does not fit into long type
8+
* therefore warning will be printed and definition will be ignored. */
9+
#define MAXIMUM_UNSIGNED_LONG 18446744073709551615
10+
#define MAXIMUM_SIGNED_LONG 9223372036854775807 // OK
11+
12+
/* negative values are currently ignored because there are 2 tokens in the
13+
* representation */
14+
// #define MINIMUM_SIGNED_LONG -9223372036854775808
15+
516
#define FLOAT 5.6
617

18+
#define INT 42
719
#define NEW_INT INT // unsupported
820

921
extern int a;

tests/samples/Define.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import scala.scalanative.native._
55

66
object DefineDefines {
77
val STRING: native.CString = c"Hello, World!"
8-
val INT = 42
9-
val FLOAT = 5.6
8+
val LONG: native.CLong = 1000000000000L
9+
val LONG_WITHOUT_ENDING: native.CLong = 1000000000000L
10+
val LONG_LONG: native.CLongLong = 1000000000000L
11+
val MAXIMUM_SIGNED_LONG: native.CLong = 9223372036854775807L
12+
val INT: native.CInt = 42
1013
val SHOULD_BE_DEFINED: native.CString = c"Because INT is not equal to 0"
1114
}

0 commit comments

Comments
 (0)