llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.84k stars 11.91k forks source link

[clang] nested `InitListExpr` has invalid `SourceRange` #99630

Open jirislaby opened 3 months ago

jirislaby commented 3 months ago

For this code:

struct B {
        int Bunused;
        union {
                int Bi;
        };
};

struct A {
        struct B Ab;
};

void do_wr(struct A *a);

void fun(int i)
{
        struct A a;

        a = (struct A) {
                .Ab.Bi = i,
        };

        do_wr(&a);
}

The inner InitListExpr (the second line here) has invalid SourceRange:

InitListExpr 0x56499f84bd00 <../test/nested-ILE.c:18:17, line:20:2> 'struct A'
`-InitListExpr 0x56499f84bd48 <<invalid sloc>, line:19:12> 'struct B'
  |-ImplicitValueInitExpr 0x56499f84bdf8 <<invalid sloc>> 'int'
  `-InitListExpr 0x56499f84bd98 <col:6, col:12> 'union B::(anonymous at ../test/nested-ILE.c:3:2)' field Field 0x56499f84b228 'Bi' 'int'
    `-ImplicitCastExpr 0x56499f84bde0 <col:12> 'int' <LValueToRValue>
      `-DeclRefExpr 0x56499f84bab0 <col:12> 'int' lvalue ParmVar 0x56499f84b850 'i' 'int'

If I do: ((InitListExpr *)0x56499f84bd48)->getSourceRange().isInvalid(), I receive false (due to obvious <invalid sloc>).

Is this expected?

BTW, it is enough to run clang like this on the code above:

clang --analyze -Xclang -ast-dump-all
jirislaby commented 3 months ago

Now I see that the beginLoc (the <invalid sloc> one) is inherited from ImplicitValueInitExpr 0x56499f84bdf8 <<invalid sloc>> 'int'. If either Bunused is removed from struct B or initialized as .Ab.Bunused = 3, it is all good.

Perhaps ImplicitValueInitExpr should be skipped when constructing SourceRanges of the surrounding InitListExpr?

llvmbot commented 3 months ago

@llvm/issue-subscribers-clang-frontend

Author: Jiri Slaby (jirislaby)

For this code: ```c struct B { int Bunused; union { int Bi; }; }; struct A { struct B Ab; }; void do_wr(struct A *a); void fun(int i) { struct A a; a = (struct A) { .Ab.Bi = i, }; do_wr(&a); } ``` The inner `InitListExpr` (the second line here) has invalid `SourceRange`: ``` InitListExpr 0x56499f84bd00 <../test/nested-ILE.c:18:17, line:20:2> 'struct A' `-InitListExpr 0x56499f84bd48 <<invalid sloc>, line:19:12> 'struct B' |-ImplicitValueInitExpr 0x56499f84bdf8 <<invalid sloc>> 'int' `-InitListExpr 0x56499f84bd98 <col:6, col:12> 'union B::(anonymous at ../test/nested-ILE.c:3:2)' field Field 0x56499f84b228 'Bi' 'int' `-ImplicitCastExpr 0x56499f84bde0 <col:12> 'int' <LValueToRValue> `-DeclRefExpr 0x56499f84bab0 <col:12> 'int' lvalue ParmVar 0x56499f84b850 'i' 'int' ``` If I do: `((InitListExpr *)0x56499f84bd48)->getSourceRange().isInvalid()`, I receive `false` (due to obvious `<invalid sloc>`). Is this expected? BTW, it is enough to run clang like this on the code above: ```sh clang --analyze -Xclang -ast-dump-all ```
shafik commented 3 months ago

Looks like ImplicitValueInitExpr always returns empty SourceLocation:

https://github.com/llvm/llvm-project/blob/22eb290a9696e2a3fd042096c61e35eca2fcce0c/clang/include/clang/AST/Expr.h#L5797-L5798

From the description that seems to make sense since they are implicit.

CC @AaronBallman

jirislaby commented 3 months ago

Looks like ImplicitValueInitExpr always returns empty SourceLocation:

Sure, no problem with that. But why is it inherited into the parent (InitListExpr). That's what I am reporting ;).

AaronBallman commented 3 months ago

Within InitListChecker::createInitListExpr(), when the CurrentObjectType is an ElaboratedType for struct B, the begin range is invalid but the end of the range is valid. This value comes from https://github.com/llvm/llvm-project/blob/a7fb25dd1fcc2e5afcc65cccfa83b7b381b48906/clang/lib/Sema/SemaInit.cpp#L2757

I've not had the chance to dig in to why the designator is created without a valid location, so hopefully someone else can pick it up from here.