This is an archive of the discontinued LLVM Phabricator instance.

[clang] Add the check of membership for the issue #58674 and improve the lookup process
ClosedPublic

Authored by lime on Feb 11 2023, 9:25 PM.

Details

Summary

This patch includes the commit 01adf96ebc86 and a fix of unhandled declaration
references.

When looking up base classes, Clang first checks whether a base class is a
template and takes the specialized template based on it. However, the base class
might be instantiated, and the above behavior can lose information.

This patch fixes the problem by first checking whether a base class is a record
declaration, so the instantiated one will be taken.

Diff Detail

Event Timeline

lime created this revision.Feb 11 2023, 9:25 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 11 2023, 9:25 PM
Herald added a subscriber: yaxunl. · View Herald Transcript
lime requested review of this revision.Feb 11 2023, 9:25 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 11 2023, 9:25 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
lime edited the summary of this revision. (Show Details)Feb 11 2023, 9:27 PM
lime updated this revision to Diff 496742.Feb 11 2023, 11:31 PM
lime added inline comments.Feb 11 2023, 11:34 PM
clang/lib/AST/CXXInheritance.cpp
85

BTW, I forgot to revert this condition last time.

lime edited the summary of this revision. (Show Details)Feb 14 2023, 1:38 AM

Thanks for working on this issue.
I don't feel confident commenting on this patch's approach (I think @erichkeane is your best bet), but the small typo does make a pretty big difference here!

clang/include/clang/AST/DeclCXX.h
1549
1553

Ditto in the rest of the patch

erichkeane accepted this revision.Feb 21 2023, 7:27 AM

I don't have a great idea of this section of code, but as code-owner I guess I'm stuck approving/disapproving of this :) Barring additional information, I think I have to accept this approach, it seems to work right, and from some time debugging, it at least doesn't seem like the 'wrong' answer here. I think the suggestion corentin made is correct and needs to be made, but otherwise I consider this acceptable.

clang/include/clang/AST/DeclCXX.h
1553

I suggest making this just LookupInDependentTypes to be more clear.

This revision is now accepted and ready to land.Feb 21 2023, 7:27 AM
lime updated this revision to Diff 499339.Feb 21 2023, 6:21 PM
lime edited the summary of this revision. (Show Details)

Updated as suggested. I will do a stage-2 build before landing the patch to confirm whether it would case another crash, and it takes time.

lime updated this revision to Diff 499374.Feb 21 2023, 11:06 PM
This revision was landed with ongoing or failed builds.Feb 22 2023, 12:45 AM
This revision was automatically updated to reflect the committed changes.

Heads up: We are experiencing a series of clang crashes because of this commit.

What we already have so far:

Unhandled DeclRefExpr
UNREACHABLE executed at clang/lib/CodeGen/CGExpr.cpp:2958!

We are now working on a reproducer.

Heads up: We are experiencing a series of clang crashes because of this commit.

What we already have so far:

Unhandled DeclRefExpr
UNREACHABLE executed at clang/lib/CodeGen/CGExpr.cpp:2958!

We are now working on a reproducer.

Here is our reproducer:

struct a {
  enum { b };
};
struct c {
  void *d;
};
struct e {
  void f(void *);
};
template <typename g> struct h : g {
  h(short, int);
  virtual void i();
};
template <typename g> void h<g>::i() { e().f(c::d); }
struct j : h<c> {
  j();
};
int k;
j::j() : h(a::b, k) {}
alexfh added a subscriber: alexfh.Feb 23 2023, 8:05 AM

Heads up: We are experiencing a series of clang crashes because of this commit.

What we already have so far:

Unhandled DeclRefExpr
UNREACHABLE executed at clang/lib/CodeGen/CGExpr.cpp:2958!

We are now working on a reproducer.

Here is our reproducer:

struct a {
  enum { b };
};
struct c {
  void *d;
};
struct e {
  void f(void *);
};
template <typename g> struct h : g {
  h(short, int);
  virtual void i();
};
template <typename g> void h<g>::i() { e().f(c::d); }
struct j : h<c> {
  j();
};
int k;
j::j() : h(a::b, k) {}

Thanks! This looks like a real problem. I'm going to revert the commit.

BTW, I managed to reduce your test case slightly more:

struct f {
  void *g;
};
template <typename j> struct k : j {
  virtual void l(){ (void)f::g; }
};
k<f> q;

https://gcc.godbolt.org/z/fa33GYf9K

This has already been reverted, but I found a breakage (not a crash) caused by this:

#include <type_traits>

class Base {
 protected:
  int member;
};

template <typename Parent>
struct Subclass : public Parent {
  static_assert(std::is_base_of<Base, Parent>::value,
                "Parent not derived from Base");
  int func() { return Base::member; }
};

using Impl = Subclass<Base>;

int use() {
  Impl i;
  return i.func();
}

gcc/msvc both accept this. But clang says:

<source>:8:29: error: 'member' is a protected member of 'Base'
  int func() { return Base::member; }
                            ^
<source>:15:12: note: in instantiation of member function 'Subclass<Base>::func' requested here
  return i.func();
           ^
<source>:3:7: note: must name member using the type of the current context 'Subclass<Base>'
  int member;
      ^

A fix is to write Parent::member instead of Base::member, but I'm wondering what the spec actually says about this, and if clang is right to reject it.