Skip to content

Conversation

@anutosh491
Copy link
Member

I added some logs to see the difference between C++ mode and C mode and I see this

In C++ mode

clang-repl> struct S1{} s1; s1
[convertExprToValue] original Expr: DeclRefExpr | type: struct S1
[convertExprToValue] Ty: struct S1
[convertExprToValue] DesugaredTy: struct S1
[convertExprToValue] Treating lvalue record as reference (enters block 540)
[convertExprToValue] Ty: struct S1 & (after block 540)
[convertExprToValue] DesugaredTy: struct S1 & (after block 540)
[computeInterfaceKind] Expr class: DeclRefExpr | isLValue: 1
(S1 &) @0x10c9ac058

in C mode

(base) anutosh491@Anutoshs-MacBook-Air bin % ./clang-repl --Xcc=-xc --Xcc=-std=c23
clang-repl> struct S1{} s1; s1
[convertExprToValue] original Expr: ImplicitCastExpr | type: struct S1
[convertExprToValue] Ty: struct S1
[convertExprToValue] DesugaredTy: struct S1
[convertExprToValue] Ty: struct S1 (after block 540)
[convertExprToValue] DesugaredTy: struct S1 (after block 540)
[computeInterfaceKind] Expr class: ImplicitCastExpr | isLValue: 0
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
s0  clang-repl               0x0000000103cca03c llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 88
1  clang-repl               0x0000000103cca61c PrintStackTraceSignalHandler(void*) + 28
2  clang-repl               0x0000000103cc7ee8 llvm::sys::RunSignalHandlers() + 152
3  clang-repl               0x0000000103ccbb54 SignalHandler(int, __siginfo*, void*) + 284
4  libsystem_platform.dylib 0x00000001887f4624 _sigtramp + 56
5  clang-repl               0x00000001079bee18 clang::Sema::CheckArgsForPlaceholders(llvm::MutableArrayRef<clang::Expr*>) + 120
6  clang-repl               0x00000001079bee18 clang::Sema::CheckArgsForPlaceholders(llvm::MutableArrayRef<clang::Expr*>) + 120
7  clang-repl               0x0000000107b823dc clang::Sema::BuildCXXNew(clang::SourceRange, bool, clang::SourceLocation, llvm::MutableArrayRef<clang::Expr*>, clang::SourceLocation, clang::SourceRange, clang::QualType, clang::TypeSourceInfo*, std::__1::optional<clang::Expr*>, clang::SourceRange, clang::Expr*) + 5672
8  clang-repl               0x000000010538c560 clang::Interpreter::convertExprToValue(clang::Expr*) + 2580
9  clang-repl               0x0000000105360774 clang::InProcessPrintingASTConsumer::HandleTopLevelDecl(clang::DeclGroupRef) + 252
10 clang-repl               0x000000010536a82c clang::IncrementalParser::ParseOrWrapTopLevelDecl() + 676
11 clang-repl               0x000000010536b554 clang::IncrementalParser::Parse(llvm::StringRef) + 712
12 clang-repl               0x000000010537e6b4 clang::Interpreter::Parse(llvm::StringRef) + 588
13 clang-repl               0x000000010537d73c clang::Interpreter::ParseAndExecute(llvm::StringRef, clang::Value*) + 72
14 clang-repl               0x000000010022db38 main + 3660
15 dyld                     0x000000018841ab98 start + 6076

So basically C mode wasn't entering block 540 as expressions like s1 (where s1 is a struct variable) are wrapped in an ImplicitCastExpr, which masks the underlying DeclRefExpr that is actually an lvalue.This patch unwraps the implicit cast with E->IgnoreImpCasts() before checking isLValue(), restoring correct detection of lvalue structs.

@anutosh491
Copy link
Member Author

Now we have

clang-repl> struct S1{} s1; s1
(S1 &) @0x10f134058
clang-repl> struct S2 {int d;} E = {22}; E
(S2 &) @0x10f140000
clang-repl> E.d
(int) 22

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 29, 2025
@anutosh491 anutosh491 changed the title Fix struct value printing for clang-repl in C mode [clang-repl] Fix struct value printing for clang-repl in C mode Oct 29, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 29, 2025

@llvm/pr-subscribers-clang

Author: Anutosh Bhat (anutosh491)

Changes

I added some logs to see the difference between C++ mode and C mode and I see this

In C++ mode

clang-repl&gt; struct S1{} s1; s1
[convertExprToValue] original Expr: DeclRefExpr | type: struct S1
[convertExprToValue] Ty: struct S1
[convertExprToValue] DesugaredTy: struct S1
[convertExprToValue] Treating lvalue record as reference (enters block 540)
[convertExprToValue] Ty: struct S1 &amp; (after block 540)
[convertExprToValue] DesugaredTy: struct S1 &amp; (after block 540)
[computeInterfaceKind] Expr class: DeclRefExpr | isLValue: 1
(S1 &amp;) @<!-- -->0x10c9ac058

in C mode

(base) anutosh491@<!-- -->Anutoshs-MacBook-Air bin % ./clang-repl --Xcc=-xc --Xcc=-std=c23
clang-repl&gt; struct S1{} s1; s1
[convertExprToValue] original Expr: ImplicitCastExpr | type: struct S1
[convertExprToValue] Ty: struct S1
[convertExprToValue] DesugaredTy: struct S1
[convertExprToValue] Ty: struct S1 (after block 540)
[convertExprToValue] DesugaredTy: struct S1 (after block 540)
[computeInterfaceKind] Expr class: ImplicitCastExpr | isLValue: 0
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
s0  clang-repl               0x0000000103cca03c llvm::sys::PrintStackTrace(llvm::raw_ostream&amp;, int) + 88
1  clang-repl               0x0000000103cca61c PrintStackTraceSignalHandler(void*) + 28
2  clang-repl               0x0000000103cc7ee8 llvm::sys::RunSignalHandlers() + 152
3  clang-repl               0x0000000103ccbb54 SignalHandler(int, __siginfo*, void*) + 284
4  libsystem_platform.dylib 0x00000001887f4624 _sigtramp + 56
5  clang-repl               0x00000001079bee18 clang::Sema::CheckArgsForPlaceholders(llvm::MutableArrayRef&lt;clang::Expr*&gt;) + 120
6  clang-repl               0x00000001079bee18 clang::Sema::CheckArgsForPlaceholders(llvm::MutableArrayRef&lt;clang::Expr*&gt;) + 120
7  clang-repl               0x0000000107b823dc clang::Sema::BuildCXXNew(clang::SourceRange, bool, clang::SourceLocation, llvm::MutableArrayRef&lt;clang::Expr*&gt;, clang::SourceLocation, clang::SourceRange, clang::QualType, clang::TypeSourceInfo*, std::__1::optional&lt;clang::Expr*&gt;, clang::SourceRange, clang::Expr*) + 5672
8  clang-repl               0x000000010538c560 clang::Interpreter::convertExprToValue(clang::Expr*) + 2580
9  clang-repl               0x0000000105360774 clang::InProcessPrintingASTConsumer::HandleTopLevelDecl(clang::DeclGroupRef) + 252
10 clang-repl               0x000000010536a82c clang::IncrementalParser::ParseOrWrapTopLevelDecl() + 676
11 clang-repl               0x000000010536b554 clang::IncrementalParser::Parse(llvm::StringRef) + 712
12 clang-repl               0x000000010537e6b4 clang::Interpreter::Parse(llvm::StringRef) + 588
13 clang-repl               0x000000010537d73c clang::Interpreter::ParseAndExecute(llvm::StringRef, clang::Value*) + 72
14 clang-repl               0x000000010022db38 main + 3660
15 dyld                     0x000000018841ab98 start + 6076

So basically C mode wasn't entering block 540 as expressions like s1 (where s1 is a struct variable) are wrapped in an ImplicitCastExpr, which masks the underlying DeclRefExpr that is actually an lvalue.This patch unwraps the implicit cast with E->IgnoreImpCasts() before checking isLValue(), restoring correct detection of lvalue structs.


Full diff: https://github.com/llvm/llvm-project/pull/165538.diff

2 Files Affected:

  • (modified) clang/lib/Interpreter/InterpreterValuePrinter.cpp (+2-2)
  • (modified) clang/test/Interpreter/pretty-print.c (+9-7)
diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
index 0ed02f3bfabe8..1e9777f3485c6 100644
--- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp
+++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
@@ -411,7 +411,7 @@ class InterfaceKindVisitor
   }
 
   InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
-    ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E);
+    ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E->IgnoreImpCasts());
     assert(!AddrOfE.isInvalid() && "Can not create unary expression");
     Args.push_back(AddrOfE.get());
     return InterfaceKind::NoAlloc;
@@ -537,7 +537,7 @@ llvm::Expected<Expr *> Interpreter::convertExprToValue(Expr *E) {
   QualType DesugaredTy = Ty.getDesugaredType(Ctx);
 
   // For lvalue struct, we treat it as a reference.
-  if (DesugaredTy->isRecordType() && E->isLValue()) {
+  if (DesugaredTy->isRecordType() && E->IgnoreImpCasts()->isLValue()) {
     DesugaredTy = Ctx.getLValueReferenceType(DesugaredTy);
     Ty = Ctx.getLValueReferenceType(Ty);
   }
diff --git a/clang/test/Interpreter/pretty-print.c b/clang/test/Interpreter/pretty-print.c
index d0712fb152107..c752b53b5264a 100644
--- a/clang/test/Interpreter/pretty-print.c
+++ b/clang/test/Interpreter/pretty-print.c
@@ -78,14 +78,16 @@ int * null_ptr = (int*)0; null_ptr
 union U { int I; float F; } u; u.I = 12; u.I
 // CHECK-NEXT: (int) 12
 
-// TODO: _Bool, _Complex, _Atomic, and _BitInt
-// struct S1{} s1; s1
-// TODO-CHECK-NEXT: (S1 &) @0x{{[0-9a-f]+}}
+struct S1{} s1; s1
+// CHECK-NEXT: (S1 &) @0x{{[0-9a-f]+}}
+
+struct S2 {int d;} E = {22}; E
+// CHECK-NEXT: (struct S2 &) @0x{{[0-9a-f]+}}
 
-// struct S2 {int d;} E = {22}; E
-// TODO-CHECK-NEXT: (struct S2 &) @0x{{[0-9a-f]+}}
-// E.d
-// TODO-CHECK-NEXT: (int) 22
+E.d
+// CHECK-NEXT: (int) 22
+
+// TODO: _Bool, _Complex, _Atomic, and _BitInt
 
 // -----------------------------------------------------------------------------
 // Tentative definition handling (C99 6.9.2)

@github-actions
Copy link

github-actions bot commented Oct 29, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@vgvassilev vgvassilev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thank you!

@anutosh491 anutosh491 merged commit ce7cca1 into llvm:main Oct 29, 2025
10 checks passed
@anutosh491 anutosh491 deleted the fix_struct_pretty_print_todo branch October 29, 2025 11:31
@anutosh491
Copy link
Member Author

Thanks for the review. Merging !

aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
…#165538)

I added some logs to see the difference between C++ mode and C mode and
I see this

In C++ mode
```
clang-repl> struct S1{} s1; s1
[convertExprToValue] original Expr: DeclRefExpr | type: struct S1
[convertExprToValue] Ty: struct S1
[convertExprToValue] DesugaredTy: struct S1
[convertExprToValue] Treating lvalue record as reference (enters block 540)
[convertExprToValue] Ty: struct S1 & (after block 540)
[convertExprToValue] DesugaredTy: struct S1 & (after block 540)
[computeInterfaceKind] Expr class: DeclRefExpr | isLValue: 1
(S1 &) @0x10c9ac058
```
in C mode
```
(base) anutosh491@Anutoshs-MacBook-Air bin % ./clang-repl --Xcc=-xc --Xcc=-std=c23
clang-repl> struct S1{} s1; s1
[convertExprToValue] original Expr: ImplicitCastExpr | type: struct S1
[convertExprToValue] Ty: struct S1
[convertExprToValue] DesugaredTy: struct S1
[convertExprToValue] Ty: struct S1 (after block 540)
[convertExprToValue] DesugaredTy: struct S1 (after block 540)
[computeInterfaceKind] Expr class: ImplicitCastExpr | isLValue: 0
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
s0  clang-repl               0x0000000103cca03c llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 88
1  clang-repl               0x0000000103cca61c PrintStackTraceSignalHandler(void*) + 28
2  clang-repl               0x0000000103cc7ee8 llvm::sys::RunSignalHandlers() + 152
3  clang-repl               0x0000000103ccbb54 SignalHandler(int, __siginfo*, void*) + 284
4  libsystem_platform.dylib 0x00000001887f4624 _sigtramp + 56
5  clang-repl               0x00000001079bee18 clang::Sema::CheckArgsForPlaceholders(llvm::MutableArrayRef<clang::Expr*>) + 120
6  clang-repl               0x00000001079bee18 clang::Sema::CheckArgsForPlaceholders(llvm::MutableArrayRef<clang::Expr*>) + 120
7  clang-repl               0x0000000107b823dc clang::Sema::BuildCXXNew(clang::SourceRange, bool, clang::SourceLocation, llvm::MutableArrayRef<clang::Expr*>, clang::SourceLocation, clang::SourceRange, clang::QualType, clang::TypeSourceInfo*, std::__1::optional<clang::Expr*>, clang::SourceRange, clang::Expr*) + 5672
8  clang-repl               0x000000010538c560 clang::Interpreter::convertExprToValue(clang::Expr*) + 2580
9  clang-repl               0x0000000105360774 clang::InProcessPrintingASTConsumer::HandleTopLevelDecl(clang::DeclGroupRef) + 252
10 clang-repl               0x000000010536a82c clang::IncrementalParser::ParseOrWrapTopLevelDecl() + 676
11 clang-repl               0x000000010536b554 clang::IncrementalParser::Parse(llvm::StringRef) + 712
12 clang-repl               0x000000010537e6b4 clang::Interpreter::Parse(llvm::StringRef) + 588
13 clang-repl               0x000000010537d73c clang::Interpreter::ParseAndExecute(llvm::StringRef, clang::Value*) + 72
14 clang-repl               0x000000010022db38 main + 3660
15 dyld                     0x000000018841ab98 start + 6076
```

So basically C mode wasn't entering block 540 as expressions like `s1`
(where `s1` is a struct variable) are wrapped in an `ImplicitCastExpr`,
which masks the underlying `DeclRefExpr` that is actually an
`lvalue`.This patch unwraps the implicit cast with E->IgnoreImpCasts()
before checking isLValue(), restoring correct detection of lvalue
structs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category clang-repl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants