This is an archive of the discontinued LLVM Phabricator instance.

[LLDB][ClangExpression] Fix initialization of static enum alias members
ClosedPublic

Authored by Michael137 on Jul 20 2022, 5:19 PM.

Details

Summary

IntegerLiteral::Create operates on integer types. For that reason
when we parse DWARF into an AST, when we encounter a constant
initialized enum member variable, we try to determine the underlying
integer type before creating the IntegerLiteral. However, we
currently don't desugar the type and for enum typedefs
dyn_cast<EnumType> fails. In debug builds this triggers following
assert:

Assertion failed: (type->isIntegerType() && "Illegal type in IntegerLiteral"), function IntegerLiteral, file Expr.cpp, line 892

This patch turns the dyn_cast<EnumType> into a getAs<EnumType>
which dyn_casts the canonical type, allowing us to get to the
underlying integer type.

Testing

  • API test
  • Manual repro is fixed

Diff Detail

Event Timeline

Michael137 created this revision.Jul 20 2022, 5:19 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 20 2022, 5:19 PM
Michael137 requested review of this revision.Jul 20 2022, 5:19 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 20 2022, 5:19 PM
  • Remove redundant header
  • Add test case
  • Remove drive-by whitespace change
  • Reword commit
Michael137 retitled this revision from [LLDB][ClangExpression] Fix evaluation of types with constant initialized enum typedefs to [LLDB][ClangExpression] Fix initialization of static enum alias members.Jul 21 2022, 3:42 AM
Michael137 edited the summary of this revision. (Show Details)
werat added a comment.EditedJul 21 2022, 4:07 AM

I've tried reproducing the test case with lldb built from HEAD on my Linux machine and it seems to work without your patch:

❯ cat ~/src/cpp/const.cc 
enum class ScopedEnum {
  scoped_enum_case1 = 1,
  scoped_enum_case2 = 2,
};

struct A {
  using EnumAlias = ScopedEnum;
  static constexpr EnumAlias e = ScopedEnum::scoped_enum_case2;
};

int main() {
    auto enum_alias_val = A::e;
}

❯ bin/lldb ~/src/cpp/a.out
(lldb) target create "/home/werat/src/cpp/a.out"
Current executable set to '/home/werat/src/cpp/a.out' (x86_64).
(lldb) b main
Breakpoint 1: where = a.out`main + 4 at const.cc:12:10, address = 0x0000000000401114
(lldb) r
Process 2767509 launched: '/home/werat/src/cpp/a.out' (x86_64)
Process 2767509 stopped
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
    frame #0: 0x0000000000401114 a.out`main at const.cc:12:10
   9    };
   10  
   11   int main() {
-> 12       auto enum_alias_val = A::e;
   13   }
(lldb) p A::e
(const A::EnumAlias) $0 = scoped_enum_case2

Maybe the test case doesn't actually hit the problem you're trying to address?


❯ bin/lldb --version
lldb version 15.0.0git (https://github.com/llvm/llvm-project.git revision 2feb99b02c886201c9774f4f24df14299105b321)
  clang revision 2feb99b02c886201c9774f4f24df14299105b321
  llvm revision 2feb99b02c886201c9774f4f24df14299105b321

I've tried reproducing the test case with lldb built from HEAD on my Linux machine and it seems to work without your patch:

❯ cat ~/src/cpp/const.cc 
enum class ScopedEnum {
  scoped_enum_case1 = 1,
  scoped_enum_case2 = 2,
};

struct A {
  using EnumAlias = ScopedEnum;
  static constexpr EnumAlias e = ScopedEnum::scoped_enum_case2;
};

int main() {
    auto enum_alias_val = A::e;
}

❯ bin/lldb ~/src/cpp/a.out
(lldb) target create "/home/werat/src/cpp/a.out"
Current executable set to '/home/werat/src/cpp/a.out' (x86_64).
(lldb) b main
Breakpoint 1: where = a.out`main + 4 at const.cc:12:10, address = 0x0000000000401114
(lldb) r
Process 2767509 launched: '/home/werat/src/cpp/a.out' (x86_64)
Process 2767509 stopped
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
    frame #0: 0x0000000000401114 a.out`main at const.cc:12:10
   9    };
   10  
   11   int main() {
-> 12       auto enum_alias_val = A::e;
   13   }
(lldb) p A::e
(const A::EnumAlias) $0 = scoped_enum_case2

Maybe the test case doesn't actually hit the problem you're trying to address?


❯ bin/lldb --version
lldb version 15.0.0git (https://github.com/llvm/llvm-project.git revision 2feb99b02c886201c9774f4f24df14299105b321)
  clang revision 2feb99b02c886201c9774f4f24df14299105b321
  llvm revision 2feb99b02c886201c9774f4f24df14299105b321

Hmm odd, on my Darwin machine the test consistently crashes

Let me confirm

aprantl accepted this revision.Jul 21 2022, 6:05 AM

@werat did you build with assertions enabled?

This change looks fine to me, but it might be interesting to see where the discrepancy between the platforms comes from.

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

In case someone else is curious what the difference between before and after is:

https://clang.llvm.org/doxygen/Type_8h_source.html#l07302

This revision is now accepted and ready to land.Jul 21 2022, 6:05 AM
Michael137 added a comment.EditedJul 21 2022, 6:11 AM

@werat did you build with assertions enabled?

This change looks fine to me, but it might be interesting to see where the discrepancy between the platforms comes from.

Interestingly, @werat's test case crashes for me (without the patch) but only if I explicitly create an instance of struct A. Otherwise, lldb doesn't find A::e.

If a class only has constexpr statics, on Darwin we omit the structure type from DWARF:

0x0000000b: DW_TAG_compile_unit            
              DW_AT_producer    ("Apple clang version 14.0.0 (clang-1400.0.25)")                           
              DW_AT_language    (DW_LANG_C_plus_plus_14)                                                   
              DW_AT_name        ("test.cpp")                                                               
              DW_AT_LLVM_sysroot        ("/Library/Developer/CommandLineTools/SDKs/MacOSX12.5.sdk")        
              DW_AT_APPLE_sdk   ("MacOSX12.5.sdk")                                                         
              DW_AT_stmt_list   (0x00000000)         
              DW_AT_comp_dir    ("/Users/michaelbuch/Git/lldb-build-lambda")                               
              DW_AT_low_pc      (0x0000000100003f9c)                                                                                                                                                                  
              DW_AT_high_pc     (0x0000000100003fb8)                                                       
                                                     
0x00000032:   DW_TAG_enumeration_type                                                                      
                DW_AT_type      (0x000000000000004b "int")                                                 
                DW_AT_enum_class        (true)                                                             
                DW_AT_name      ("ScopedEnum")                                                             
                DW_AT_byte_size (0x04)               
                DW_AT_decl_file ("/Users/michaelbuch/Git/lldb-build-lambda/test.cpp")                      
                DW_AT_decl_line (1)                                                                        
                                                     
0x0000003e:     DW_TAG_enumerator                                                                          
                  DW_AT_name    ("scoped_enum_case1")
                  DW_AT_const_value     (1)                                                                
                                                                                                           
0x00000044:     DW_TAG_enumerator                    
                  DW_AT_name    ("scoped_enum_case2")                                                      
                  DW_AT_const_value     (2)                                                                
                                                                                                           
0x0000004a:     NULL                                                                                       
                                                                                                           
0x0000004b:   DW_TAG_base_type                                                                             
                DW_AT_name      ("int")                                                                    
                DW_AT_encoding  (DW_ATE_signed)                                                            
                DW_AT_byte_size (0x04)                                                                     
                                                                                                           
0x00000052:   DW_TAG_subprogram                                                                            
                DW_AT_low_pc    (0x0000000100003f9c) 
                DW_AT_high_pc   (0x0000000100003fb8)                                                       
                DW_AT_APPLE_omit_frame_ptr      (true)                                                                                                                                                                
                DW_AT_frame_base        (DW_OP_reg31 WSP)                                                  
                DW_AT_name      ("main")
                DW_AT_decl_file ("/Users/michaelbuch/Git/lldb-build-lambda/test.cpp")                      
                DW_AT_decl_line (13)                                                                       
                DW_AT_type      (0x000000000000004b "int")                                                 
                DW_AT_external  (true)

0x0000006b:     DW_TAG_variable
                  DW_AT_location        (DW_OP_fbreg +8)                                                   
                  DW_AT_name    ("enum_alias_val")
                  DW_AT_decl_file       ("/Users/michaelbuch/Git/lldb-build-lambda/test.cpp")              
                  DW_AT_decl_line       (14)
                  DW_AT_type    (0x0000000000000032 "ScopedEnum")                                          

0x00000079:     NULL                                 

0x0000007a:   NULL

This is actually noted in one of the test cases in TestConstStaticIntegralMember.py:

# dsymutil strips the debug info for classes that only have const static
# data members without a definition namespace scope.                    
@expectedFailureAll(debug_info=["dsym"])                                
def test_class_with_only_const_static(self):

Though I'm a little confused why the test does find ClassWithEnumAlias::enum_alias despite it not being instantiated in main

Though I'm a little confused why the test does find ClassWithEnumAlias::enum_alias despite it not being instantiated in main

Oh nvm, probably just because clang++ on Darwin invokes dsymutil at the end. Whereas in the test suite we don't unless explicitly done

werat added a comment.Jul 21 2022, 6:54 AM

@werat did you build with assertions enabled?

Oh, no, I build in RelWithDebInfo out of habit. I've tried with assertions and then it fails.

However, when ignoring the asserts the result is correct, which makes me wonder whether the assert check is 100% correct.