Skip to content

Commit 703232b

Browse files
committed
Automatically pick integer literal type
1 parent 578d43d commit 703232b

File tree

5 files changed

+148
-41
lines changed

5 files changed

+148
-41
lines changed

lldb/include/lldb/ValueObject/DILAST.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,36 @@ class BitFieldExtractionNode : public ASTNode {
181181

182182
class ScalarLiteralNode : public ASTNode {
183183
public:
184-
ScalarLiteralNode(uint32_t location, lldb::BasicType type, Scalar value)
185-
: ASTNode(location, NodeKind::eScalarLiteralNode), m_type(type),
186-
m_value(value) {}
184+
ScalarLiteralNode(uint32_t location, Scalar value, uint32_t radix,
185+
bool is_unsigned, bool is_long, bool is_longlong)
186+
: ASTNode(location, NodeKind::eScalarLiteralNode), m_value(value),
187+
m_radix(radix), m_is_unsigned(is_unsigned), m_is_long(is_long),
188+
m_is_longlong(is_longlong) {}
189+
190+
ScalarLiteralNode(uint32_t location, Scalar value, bool is_float)
191+
: ASTNode(location, NodeKind::eScalarLiteralNode), m_value(value),
192+
m_is_float(is_float) {}
187193

188194
llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
189195

190-
lldb::BasicType GetType() const { return m_type; }
191196
Scalar GetValue() const & { return m_value; }
197+
uint32_t GetRadix() const { return m_radix; }
198+
bool IsUnsigned() const { return m_is_unsigned; }
199+
bool IsLong() const { return m_is_long; }
200+
bool IsLongLong() const { return m_is_longlong; }
201+
bool IsFloat() const { return m_is_float; }
192202

193203
static bool classof(const ASTNode *node) {
194204
return node->GetKind() == NodeKind::eScalarLiteralNode;
195205
}
196206

197207
private:
198-
lldb::BasicType m_type;
199208
Scalar m_value;
209+
uint32_t m_radix;
210+
bool m_is_unsigned;
211+
bool m_is_long;
212+
bool m_is_longlong;
213+
bool m_is_float;
200214
};
201215

202216
/// This class contains one Visit method for each specialized type of

lldb/include/lldb/ValueObject/DILEval.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ class Interpreter : Visitor {
5757
llvm::Expected<lldb::ValueObjectSP>
5858
Visit(const ScalarLiteralNode *node) override;
5959

60+
llvm::Expected<CompilerType>
61+
PickLiteralType(lldb::TypeSystemSP type_system,
62+
std::shared_ptr<ExecutionContextScope> ctx,
63+
const ScalarLiteralNode *literal);
64+
6065
// Used by the interpreter to create objects, perform casts, etc.
6166
lldb::TargetSP m_target;
6267
llvm::StringRef m_expr;

lldb/source/ValueObject/DILEval.cpp

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,7 @@ Interpreter::Visit(const BitFieldExtractionNode *node) {
404404
return child_valobj_sp;
405405
}
406406

407-
static CompilerType GetBasicTypeFromCU(std::shared_ptr<StackFrame> ctx,
408-
lldb::BasicType basic_type) {
407+
static lldb::TypeSystemSP GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
409408
SymbolContext symbol_context =
410409
ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
411410
auto language = symbol_context.comp_unit->GetLanguage();
@@ -414,20 +413,103 @@ static CompilerType GetBasicTypeFromCU(std::shared_ptr<StackFrame> ctx,
414413
auto type_system =
415414
symbol_context.module_sp->GetTypeSystemForLanguage(language);
416415

416+
if (type_system)
417+
return *type_system;
418+
419+
return lldb::TypeSystemSP();
420+
}
421+
422+
static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
423+
lldb::BasicType basic_type) {
417424
if (type_system)
418425
if (auto compiler_type = type_system.get()->GetBasicTypeFromAST(basic_type))
419426
return compiler_type;
420427

421-
return CompilerType();
428+
CompilerType empty_type;
429+
return empty_type;
430+
}
431+
432+
llvm::Expected<CompilerType>
433+
Interpreter::PickLiteralType(lldb::TypeSystemSP type_system,
434+
std::shared_ptr<ExecutionContextScope> ctx,
435+
const ScalarLiteralNode *literal) {
436+
Scalar scalar = literal->GetValue();
437+
if (scalar.GetType() == Scalar::e_float) {
438+
if (literal->IsFloat())
439+
return GetBasicType(type_system, lldb::eBasicTypeFloat);
440+
return GetBasicType(type_system, lldb::eBasicTypeDouble);
441+
} else if (scalar.GetType() == Scalar::e_int) {
442+
// Binary, Octal, Hexadecimal and literals with a U suffix are allowed to be
443+
// an unsigned integer.
444+
bool unsigned_is_allowed =
445+
literal->IsUnsigned() || literal->GetRadix() != 10;
446+
447+
// Try int/unsigned int.
448+
uint64_t int_byte_size = 0;
449+
if (auto temp = GetBasicType(type_system, lldb::eBasicTypeInt)
450+
.GetByteSize(ctx.get()))
451+
int_byte_size = *temp;
452+
unsigned int_size = int_byte_size * CHAR_BIT;
453+
llvm::APInt apint = scalar.GetAPSInt();
454+
if (!literal->IsLong() && !literal->IsLongLong() &&
455+
apint.isIntN(int_size)) {
456+
if (!literal->IsUnsigned() && apint.isIntN(int_size - 1))
457+
return GetBasicType(type_system, lldb::eBasicTypeInt);
458+
if (unsigned_is_allowed)
459+
return GetBasicType(type_system, lldb::eBasicTypeUnsignedInt);
460+
}
461+
// Try long/unsigned long.
462+
uint64_t long_byte_size = 0;
463+
if (auto temp = GetBasicType(type_system, lldb::eBasicTypeLong)
464+
.GetByteSize(ctx.get()))
465+
long_byte_size = *temp;
466+
unsigned long_size = long_byte_size * CHAR_BIT;
467+
if (!literal->IsLongLong() && apint.isIntN(long_size)) {
468+
if (!literal->IsUnsigned() && apint.isIntN(long_size - 1))
469+
return GetBasicType(type_system, lldb::eBasicTypeLong);
470+
if (unsigned_is_allowed)
471+
return GetBasicType(type_system, lldb::eBasicTypeUnsignedLong);
472+
}
473+
// Try long long/unsigned long long.
474+
uint64_t long_long_byte_size = 0;
475+
if (auto temp = GetBasicType(type_system, lldb::eBasicTypeLongLong)
476+
.GetByteSize(ctx.get()))
477+
long_long_byte_size = *temp;
478+
unsigned long_long_size = long_long_byte_size * CHAR_BIT;
479+
if (apint.isIntN(long_long_size)) {
480+
if (!literal->IsUnsigned() && apint.isIntN(long_long_size - 1))
481+
return GetBasicType(type_system, lldb::eBasicTypeLongLong);
482+
// If we still couldn't decide a type, we probably have something that
483+
// does not fit in a signed long long, but has no U suffix. Also known as:
484+
//
485+
// warning: integer literal is too large to be represented in a signed
486+
// integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal]
487+
//
488+
return GetBasicType(type_system, lldb::eBasicTypeUnsignedLongLong);
489+
}
490+
return llvm::make_error<DILDiagnosticError>(
491+
m_expr,
492+
"integer literal is too large to be represented in any integer type",
493+
literal->GetLocation());
494+
}
495+
return llvm::make_error<DILDiagnosticError>(
496+
m_expr, "unable to create a const literal", literal->GetLocation());
422497
}
423498

424499
llvm::Expected<lldb::ValueObjectSP>
425500
Interpreter::Visit(const ScalarLiteralNode *node) {
426-
CompilerType result_type =
427-
GetBasicTypeFromCU(m_exe_ctx_scope, node->GetType());
428-
Scalar value = node->GetValue();
429-
return ValueObject::CreateValueObjectFromScalar(m_target, value, result_type,
430-
"result");
501+
auto type_system = GetTypeSystemFromCU(m_exe_ctx_scope);
502+
if (type_system) {
503+
auto type = PickLiteralType(type_system, m_exe_ctx_scope, node);
504+
if (type) {
505+
Scalar scalar = node->GetValue();
506+
return ValueObject::CreateValueObjectFromScalar(m_target, scalar, *type,
507+
"result");
508+
} else
509+
return type.takeError();
510+
}
511+
return llvm::make_error<DILDiagnosticError>(
512+
m_expr, "unable to create a const literal", node->GetLocation());
431513
}
432514

433515
} // namespace lldb_private::dil

lldb/source/ValueObject/DILParser.cpp

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -396,30 +396,26 @@ ASTNodeUP DILParser::ParseNumericLiteral() {
396396
return numeric_constant;
397397
}
398398

399-
static constexpr std::pair<const char *, lldb::BasicType> type_suffixes[] = {
400-
{"ull", lldb::eBasicTypeUnsignedLongLong},
401-
{"ul", lldb::eBasicTypeUnsignedLong},
402-
{"u", lldb::eBasicTypeUnsignedInt},
403-
{"ll", lldb::eBasicTypeLongLong},
404-
{"l", lldb::eBasicTypeLong},
405-
};
406-
407399
ASTNodeUP DILParser::ParseIntegerLiteral() {
408400
Token token = CurToken();
409401
auto spelling = token.GetSpelling();
410402
llvm::StringRef spelling_ref = spelling;
411-
lldb::BasicType type = lldb::eBasicTypeInt;
412-
for (auto [suffix, t] : type_suffixes) {
413-
if (spelling_ref.consume_back_insensitive(suffix)) {
414-
type = t;
415-
break;
416-
}
417-
}
403+
404+
auto radix = llvm::getAutoSenseRadix(spelling_ref);
405+
bool is_unsigned = false, is_long = false, is_longlong = false;
406+
if (spelling_ref.consume_back_insensitive("ll"))
407+
is_longlong = true;
408+
if (spelling_ref.consume_back_insensitive("l"))
409+
is_long = true;
410+
if (spelling_ref.consume_back_insensitive("u"))
411+
is_unsigned = true;
412+
418413
llvm::APInt raw_value;
419-
if (!spelling_ref.getAsInteger(0, raw_value)) {
414+
if (!spelling_ref.getAsInteger(radix, raw_value)) {
420415
Scalar scalar_value(raw_value);
421-
return std::make_unique<ScalarLiteralNode>(token.GetLocation(), type,
422-
scalar_value);
416+
return std::make_unique<ScalarLiteralNode>(token.GetLocation(),
417+
scalar_value, radix, is_unsigned,
418+
is_long, is_longlong);
423419
}
424420
return std::make_unique<ErrorNode>();
425421
}
@@ -428,19 +424,20 @@ ASTNodeUP DILParser::ParseFloatingPointLiteral() {
428424
Token token = CurToken();
429425
auto spelling = token.GetSpelling();
430426
llvm::StringRef spelling_ref = spelling;
431-
spelling_ref = spelling;
432-
lldb::BasicType type = lldb::eBasicTypeDouble;
427+
428+
bool is_float = false;
433429
llvm::APFloat raw_float(llvm::APFloat::IEEEdouble());
434430
if (spelling_ref.consume_back_insensitive("f")) {
435-
type = lldb::eBasicTypeFloat;
431+
is_float = true;
436432
raw_float = llvm::APFloat(llvm::APFloat::IEEEsingle());
437433
}
434+
438435
auto StatusOrErr = raw_float.convertFromString(
439436
spelling_ref, llvm::APFloat::rmNearestTiesToEven);
440437
if (!errorToBool(StatusOrErr.takeError())) {
441438
Scalar scalar_value(raw_float);
442-
return std::make_unique<ScalarLiteralNode>(token.GetLocation(), type,
443-
scalar_value);
439+
return std::make_unique<ScalarLiteralNode>(token.GetLocation(),
440+
scalar_value, is_float);
444441
}
445442
return std::make_unique<ErrorNode>();
446443
}

lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,20 @@ def test_arithmetic(self):
2020
self.runCmd("settings set target.experimental.use-DIL true")
2121

2222
# Check number parsing
23-
self.expect_var_path("1", value="1", type="int")
24-
self.expect_var_path("1ull", value="1", type="unsigned long long")
25-
self.expect_var_path("0b10", value="2", type="int")
26-
self.expect_var_path("010", value="8", type="int")
27-
self.expect_var_path("0x10", value="16", type="int")
2823
self.expect_var_path("1.0", value="1", type="double")
2924
self.expect_var_path("1.0f", value="1", type="float")
3025
self.expect_var_path("0x1.2p+3f", value="9", type="float")
26+
self.expect_var_path("1", value="1", type="int")
27+
self.expect_var_path("1u", value="1", type="unsigned int")
28+
self.expect_var_path("0b1l", value="1", type="long")
29+
self.expect_var_path("01ul", value="1", type="unsigned long")
30+
self.expect_var_path("0o1ll", value="1", type="long long")
31+
self.expect_var_path("0x1ULL", value="1", type="unsigned long long")
32+
self.expect_var_path("0xFFFFFFFFFFFFFFFF", value="18446744073709551615")
33+
self.expect(
34+
"frame var '0xFFFFFFFFFFFFFFFFF'",
35+
error=True,
36+
substrs=[
37+
"integer literal is too large to be represented in any integer type"
38+
],
39+
)

0 commit comments

Comments
 (0)