Skip to content

Commit 5290832

Browse files
committed
[lldb] Analyze enum promotion type during parsing
1 parent b2d2494 commit 5290832

File tree

3 files changed

+100
-26
lines changed

3 files changed

+100
-26
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3891,6 +3891,7 @@ class EnumDecl : public TagDecl {
38913891
void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
38923892
TemplateSpecializationKind TSK);
38933893

3894+
public:
38943895
/// Sets the width in bits required to store all the
38953896
/// non-negative enumerators of this enum.
38963897
void setNumPositiveBits(unsigned Num) {
@@ -3902,7 +3903,6 @@ class EnumDecl : public TagDecl {
39023903
/// negative enumerators of this enum. (see getNumNegativeBits)
39033904
void setNumNegativeBits(unsigned Num) { EnumDeclBits.NumNegativeBits = Num; }
39043905

3905-
public:
39063906
/// True if this tag declaration is a scoped enumeration. Only
39073907
/// possible in C++11 mode.
39083908
void setScoped(bool Scoped = true) { EnumDeclBits.IsScoped = Scoped; }

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2248,6 +2248,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
22482248
return 0;
22492249

22502250
size_t enumerators_added = 0;
2251+
unsigned NumNegativeBits = 0;
2252+
unsigned NumPositiveBits = 0;
22512253

22522254
for (DWARFDIE die : parent_die.children()) {
22532255
const dw_tag_t tag = die.Tag();
@@ -2299,11 +2301,102 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
22992301
}
23002302

23012303
if (name && name[0] && got_value) {
2302-
m_ast.AddEnumerationValueToEnumerationType(
2304+
auto ECD = m_ast.AddEnumerationValueToEnumerationType(
23032305
clang_type, decl, name, enum_value, enumerator_byte_size * 8);
23042306
++enumerators_added;
2307+
2308+
llvm::APSInt InitVal = ECD->getInitVal();
2309+
// Keep track of the size of positive and negative values.
2310+
if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
2311+
// If the enumerator is zero that should still be counted as a positive
2312+
// bit since we need a bit to store the value zero.
2313+
unsigned ActiveBits = InitVal.getActiveBits();
2314+
NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
2315+
} else {
2316+
NumNegativeBits =
2317+
std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
2318+
}
23052319
}
23062320
}
2321+
2322+
/// The following code follows the same logic as in Sema::ActOnEnumBody
2323+
/// clang/lib/Sema/SemaDecl.cpp
2324+
// If we have an empty set of enumerators we still need one bit.
2325+
// From [dcl.enum]p8
2326+
// If the enumerator-list is empty, the values of the enumeration are as if
2327+
// the enumeration had a single enumerator with value 0
2328+
if (!NumPositiveBits && !NumNegativeBits)
2329+
NumPositiveBits = 1;
2330+
2331+
clang::QualType qual_type(ClangUtil::GetQualType(clang_type));
2332+
clang::EnumDecl *enum_decl = qual_type->getAs<clang::EnumType>()->getDecl();
2333+
enum_decl->setNumPositiveBits(NumPositiveBits);
2334+
enum_decl->setNumNegativeBits(NumNegativeBits);
2335+
2336+
// C++0x N3000 [conv.prom]p3:
2337+
// An rvalue of an unscoped enumeration type whose underlying
2338+
// type is not fixed can be converted to an rvalue of the first
2339+
// of the following types that can represent all the values of
2340+
// the enumeration: int, unsigned int, long int, unsigned long
2341+
// int, long long int, or unsigned long long int.
2342+
// C99 6.4.4.3p2:
2343+
// An identifier declared as an enumeration constant has type int.
2344+
// The C99 rule is modified by C23.
2345+
clang::QualType BestPromotionType;
2346+
unsigned BestWidth;
2347+
2348+
auto &Context = m_ast.getASTContext();
2349+
unsigned LongWidth = Context.getTargetInfo().getLongWidth();
2350+
unsigned IntWidth = Context.getTargetInfo().getIntWidth();
2351+
unsigned CharWidth = Context.getTargetInfo().getCharWidth();
2352+
unsigned ShortWidth = Context.getTargetInfo().getShortWidth();
2353+
2354+
bool is_cpp = Language::LanguageIsCPlusPlus(
2355+
SymbolFileDWARF::GetLanguage(*parent_die.GetCU()));
2356+
2357+
if (NumNegativeBits) {
2358+
// If there is a negative value, figure out the smallest integer type (of
2359+
// int/long/longlong) that fits.
2360+
if (NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) {
2361+
BestWidth = CharWidth;
2362+
} else if (NumNegativeBits <= ShortWidth && NumPositiveBits < ShortWidth) {
2363+
BestWidth = ShortWidth;
2364+
} else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
2365+
BestWidth = IntWidth;
2366+
} else if (NumNegativeBits <= LongWidth && NumPositiveBits < LongWidth) {
2367+
BestWidth = LongWidth;
2368+
} else {
2369+
BestWidth = Context.getTargetInfo().getLongLongWidth();
2370+
}
2371+
BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : qual_type);
2372+
} else {
2373+
// If there is no negative value, figure out the smallest type that fits
2374+
// all of the enumerator values.
2375+
if (NumPositiveBits <= CharWidth) {
2376+
BestPromotionType = Context.IntTy;
2377+
BestWidth = CharWidth;
2378+
} else if (NumPositiveBits <= ShortWidth) {
2379+
BestPromotionType = Context.IntTy;
2380+
BestWidth = ShortWidth;
2381+
} else if (NumPositiveBits <= IntWidth) {
2382+
BestWidth = IntWidth;
2383+
BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
2384+
? Context.UnsignedIntTy
2385+
: Context.IntTy;
2386+
} else if (NumPositiveBits <= LongWidth) {
2387+
BestWidth = LongWidth;
2388+
BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
2389+
? Context.UnsignedLongTy
2390+
: Context.LongTy;
2391+
} else {
2392+
BestWidth = Context.getTargetInfo().getLongLongWidth();
2393+
BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
2394+
? Context.UnsignedLongLongTy
2395+
: Context.LongLongTy;
2396+
}
2397+
}
2398+
enum_decl->setPromotionType(BestPromotionType);
2399+
23072400
return enumerators_added;
23082401
}
23092402

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2341,7 +2341,6 @@ CompilerType TypeSystemClang::CreateEnumerationType(
23412341
if (decl_ctx)
23422342
decl_ctx->addDecl(enum_decl);
23432343

2344-
// TODO: check if we should be setting the promotion type too?
23452344
enum_decl->setIntegerType(ClangUtil::GetQualType(integer_clang_type));
23462345

23472346
enum_decl->setAccess(AS_public); // TODO respect what's in the debug info
@@ -8461,30 +8460,11 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition(
84618460
if (enum_decl->isCompleteDefinition())
84628461
return true;
84638462

8464-
clang::ASTContext &ast = lldb_ast->getASTContext();
8465-
8466-
/// TODO This really needs to be fixed.
8467-
84688463
QualType integer_type(enum_decl->getIntegerType());
84698464
if (!integer_type.isNull()) {
8470-
unsigned NumPositiveBits = 1;
8471-
unsigned NumNegativeBits = 0;
8472-
8473-
clang::QualType promotion_qual_type;
8474-
// If the enum integer type is less than an integer in bit width,
8475-
// then we must promote it to an integer size.
8476-
if (ast.getTypeSize(enum_decl->getIntegerType()) <
8477-
ast.getTypeSize(ast.IntTy)) {
8478-
if (enum_decl->getIntegerType()->isSignedIntegerType())
8479-
promotion_qual_type = ast.IntTy;
8480-
else
8481-
promotion_qual_type = ast.UnsignedIntTy;
8482-
} else
8483-
promotion_qual_type = enum_decl->getIntegerType();
8484-
8485-
enum_decl->completeDefinition(enum_decl->getIntegerType(),
8486-
promotion_qual_type, NumPositiveBits,
8487-
NumNegativeBits);
8465+
enum_decl->completeDefinition(
8466+
enum_decl->getIntegerType(), enum_decl->getPromotionType(),
8467+
enum_decl->getNumPositiveBits(), enum_decl->getNumNegativeBits());
84888468
}
84898469
return true;
84908470
}
@@ -8544,7 +8524,8 @@ clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType(
85448524
bool is_signed = false;
85458525
underlying_type.IsIntegerType(is_signed);
85468526

8547-
llvm::APSInt value(enum_value_bit_size, is_signed);
8527+
// APSInt constructor's sign argument is isUnsigned
8528+
llvm::APSInt value(enum_value_bit_size, !is_signed);
85488529
value = enum_value;
85498530

85508531
return AddEnumerationValueToEnumerationType(enum_type, decl, name, value);

0 commit comments

Comments
 (0)