This is an archive of the discontinued LLVM Phabricator instance.

[Sema][TreeTransform] Re-create DesignatedInitExpr when it has a field designator with a valid FieldDecl
ClosedPublic

Authored by arphaman on Oct 19 2016, 10:13 AM.

Details

Summary

This patch fixes an invalid Winitializer-overrides warning that's shown for a piece of code like this:

template <typename T> struct Foo {
  struct SubFoo {
    int bar1;
    int bar2;
  };

  static void Test() { 
   SubFoo sf = {.bar1 = 10, 
   // Incorrect "initializer overrides prior initialization" warning shown on the line below when instantiating Foo<bool>
                         .bar2 = 20}; 
  }
};

void foo() {
  Foo<int>::Test();
  Foo<bool>::Test();
}

The invalid warning is shown because in the second instantiation of Foo<T>::Test the DesignatedInitExpr that corresponds to the initializer for sf has a field designator with a pointer to the FieldDecl from the first instantiation of Foo<T>::SubFoo, which is incorrect in the context of the second instantiation. This means that InitListChecker::CheckDesignatedInitializer isn't able to find the correct FieldIndex for the correct field in the initialized record, leading to an incorrect warning.

This patch fixes this bug by ensuring that a DesignatedInitExpr is re-created by the tree-transformer when it has a field designator with a FieldDecl that has been already been set. This means that in the example above the DesignatedInitExpr won't be re-created by the tree-transformer in the first instantiation, but it will be re-created in the second instantiation, thus ensuring that the second instantiation doesn't have the incorrect FieldDecl pointers.

Diff Detail

Repository
rL LLVM

Event Timeline

arphaman updated this revision to Diff 75162.Oct 19 2016, 10:13 AM
arphaman retitled this revision from to [Sema][TreeTransform] Re-create DesignatedInitExpr when it has a field designator with a valid FieldDecl.
arphaman updated this object.
arphaman added reviewers: rjmccall, manmanren.
arphaman set the repository for this revision to rL LLVM.
arphaman added a subscriber: cfe-commits.
manmanren edited edge metadata.Oct 19 2016, 2:52 PM

It makes sense to rebuild the expression when a field designator stores a FieldDecl.

Thanks for working on this!
Manman

lib/Sema/TreeTransform.h
8926 ↗(On Diff #75162)

Please add comment here on why we need to set ExprChanged to true.

arphaman updated this revision to Diff 75279.Oct 20 2016, 3:37 AM
arphaman edited edge metadata.
arphaman marked an inline comment as done.

The updated patch adds a comment to the modified code as request by Manman.

rjmccall edited edge metadata.Oct 20 2016, 10:25 AM

The fact that this bug only arises when performing a *second* instantiation suggests that there's a deeper bug here, because template instantiation is not supposed to modify the pattern AST. In this case, the basic problem is that, when the parser processes a designator, it only has an identifier, not a FieldDecl*, because it doesn't know what type is being initialized yet. SemaInit eventually resolves that identifier to a FieldDecl and needs to record that in the AST; typically the AST is treated as immutable, but in this case, instead of cloning the expression, Sema just modifies the field designator in-place. That's not completely unreasonable, and it's definitely the most space-efficient solution for non-template code-building; but in template code, it does mean that we have to take care to not present the same unresolved field designator to Sema twice.

Fortunately, this is pretty easy: we just need to need to flag the expression as needing rebuilding when there isn't a resolved field in the field designator. When there *is* a resolved field, we just need to map it using TransformDecl; the expression then only needs to be rebuilt if that fails or returns a different declaration.

The fact that this bug only arises when performing a *second* instantiation suggests that there's a deeper bug here, because template instantiation is not supposed to modify the pattern AST. In this case, the basic problem is that, when the parser processes a designator, it only has an identifier, not a FieldDecl*, because it doesn't know what type is being initialized yet. SemaInit eventually resolves that identifier to a FieldDecl and needs to record that in the AST; typically the AST is treated as immutable, but in this case, instead of cloning the expression, Sema just modifies the field designator in-place. That's not completely unreasonable, and it's definitely the most space-efficient solution for non-template code-building; but in template code, it does mean that we have to take care to not present the same unresolved field designator to Sema twice.

Fortunately, this is pretty easy: we just need to need to flag the expression as needing rebuilding when there isn't a resolved field in the field designator. When there *is* a resolved field, we just need to map it using TransformDecl; the expression then only needs to be rebuilt if that fails or returns a different declaration.

You're right, the point that you made about modifying the pattern AST is correct. I will update the patch accordingly.

arphaman updated this revision to Diff 75414.Oct 21 2016, 4:55 AM
arphaman edited edge metadata.

The updated patch addresses John's comment by modifying the DesignatedInitExpr re-creation logic.

Thanks, LGTM with a small tweak.

lib/Sema/TreeTransform.h
8928 ↗(On Diff #75414)

I'm pretty sure that TransformDecl promises to preserve the decl kind, i.e. this can be a cast_or_null.

This revision was automatically updated to reflect the committed changes.
arphaman marked an inline comment as done.