This is an archive of the discontinued LLVM Phabricator instance.

[clang][ConstExprEmitter] handle NullToPointer ImplicitCastExpr
ClosedPublic

Authored by nickdesaulniers on Jul 24 2023, 3:23 PM.

Details

Summary

Consider the following statement:

void* foo = ((void *)0);

For the sub-AST:

| `-ImplicitCastExpr 'const void *' <NullToPointer>
|   `-CStyleCastExpr 'void *' <NullToPointer>
|     `-IntegerLiteral 'int' 0

If the subexpression of the cast is itself the NULL constant, then
ImplicitCastExpr should emit the NULL pointer constant.

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald TranscriptJul 24 2023, 3:23 PM
Herald added a subscriber: inglorion. · View Herald Transcript
nickdesaulniers requested review of this revision.Jul 24 2023, 3:23 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 24 2023, 3:23 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
clang/lib/CodeGen/CGExprConstant.cpp
1131–1132

FWIW, I would have thought these might be unnecessary, but we do trip 2 tests without these guards IIRC.

efriedma added inline comments.Jul 24 2023, 4:29 PM
clang/lib/CodeGen/CGExprConstant.cpp
1131–1132

The fact that the Visit can fail doesn't surprise me; you can write arbitrary expressions of type nullptr_t (for example, nullptr_t f(); void* g = f();. I can't think of any reason you'd need to check C->isNullValue(), though; do you have a testcase for that?

clang/lib/CodeGen/CGExprConstant.cpp
1131–1132

Failed Tests (2):

Clang :: CodeGenCXX/const-init-cxx11.cpp
Clang :: CodeGenCXX/cxx11-thread-local-instantiated.cpp

Looking at the first:

decltype(nullptr) null();
int *p = null();

and the corresponding AST:

|-FunctionDecl 0x5650ebbb44a8 <x.cpp:2:3, col:26> col:21 used null 'decltype(nullptr) ()'
`-VarDecl 0x5650ebbb45e0 <line:3:3, col:17> col:8 p 'int *' cinit
  `-ImplicitCastExpr 0x5650ebbb4740 <col:12, col:17> 'int *' <NullToPointer>
    `-CallExpr 0x5650ebbb4720 <col:12, col:17> 'decltype(nullptr)':'std::nullptr_t'
      `-ImplicitCastExpr 0x5650ebbb4708 <col:12> 'decltype(nullptr) (*)()' <FunctionToPointerDecay>
        `-DeclRefExpr 0x5650ebbb4690 <col:12> 'decltype(nullptr) ()' lvalue Function 0x5650ebbb44a8 'null' 'decltype(nullptr) ()'

we change the existing test case from having a __cxx_global_var_init routine, i.e.:

@p = dso_local global ptr null, align 8
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_x.cpp, ptr null }]

; Function Attrs: noinline uwtable
define internal void @__cxx_global_var_init() #0 section ".text.startup" {
entry:
  %call = call ptr @_Z4nullv()
  store ptr null, ptr @p, align 8
  ret void
}

declare ptr @_Z4nullv() #1

; Function Attrs: noinline uwtable
define internal void @_GLOBAL__sub_I_x.cpp() #0 section ".text.startup" {
entry:
  call void @__cxx_global_var_init()
  ret void
}

to simply:

@p = dso_local global ptr null, align 8

So it seems nice to skip having the static constructors, but then @_Z4nullv is never invoked. That seems problematic? (I expect the fast path to fail once it recurses down to the DeclRefExpr, but that requires the subexpr of the ImplicitCastExpr be visited).


So I think the code as written is good to go. WDYT?

efriedma added inline comments.Jul 25 2023, 3:00 PM
clang/lib/CodeGen/CGExprConstant.cpp
1131–1132

I think you need to check that Visit() succeeds (returns a non-null Constant*), but like I said before, I can't see why you need to check C->isNullValue()

nickdesaulniers marked 2 inline comments as done.
  • remove the check for isNullValue as per @efriedma
clang/lib/CodeGen/CGExprConstant.cpp
1131–1132

oh, sorry, my reading comprehension skills are sliding off a cliff.

Yeah, that's not necessary for test cases in tree. Removed.

This revision is now accepted and ready to land.Jul 26 2023, 11:35 AM
This revision was landed with ongoing or failed builds.Jul 26 2023, 12:53 PM
This revision was automatically updated to reflect the committed changes.