Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

clang-format confused with class template parametrized by enums #47407

Open Quuxplusone opened 3 years ago

Quuxplusone commented 3 years ago
Bugzilla Link PR48438
Status NEW
Importance P normal
Reported by Mateusz Lewicki (mateuszalewicki@gmail.com)
Reported on 2020-12-08 01:20:30 -0800
Last modified on 2020-12-15 12:34:52 -0800
Version 10.0
Hardware PC Linux
CC djasper@google.com, klimek@google.com, llvm-bugs@lists.llvm.org, mateuszalewicki@gmail.com, mydeveloperday@gmail.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also

Following code is strangely formatted in clang-format 8, 10, 11 (from Ubuntu repo) with llvm style:

template <enum AAAA aaa, BBBB bbb, enum CCC ccc>
class DDD : public EEE, public FFFF {
  public : static constexpr GGG ggg = ccc; static constexpr HHH hhh = ggg;
}
}
;
}

Removing enum from enum CCC gives much better output:

template <enum AAAA aaa, BBBB bbb, CCC ccc>
class DDD : public EEE, public FFFF {
public:
  static constexpr GGG ggg = ccc;
  static constexpr HHH hhh = ggg;
}
}
;
}

Though ; in separate line still looks strange.

Possibly related to https://bugs.llvm.org/show_bug.cgi?id=48305 Both originate in my project, both have problems with mismatching parentheses and both are worked-around by removing something. I concede this may be far-fetched connection.

Quuxplusone commented 3 years ago
Why do you think

}
;
}

is strange, there is no match braces for those? were you expecting it to do
something else?
Quuxplusone commented 3 years ago
I can see why its going wrong but I'm not sure how its got into that state

If I break the problem down to

template <typename T, enum B>
class D {
  public : static constexpr A g = 1; static constexpr B h = 2;
}

The the { after the D gets incorrectly set at a DictLiteral

 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=0 Name=template L=8 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561a6bda8 Text='template'
 M=0 C=0 T=TemplateOpener S=1 F=0 B=0 BK=0 P=30 Name=less L=10 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='<'
 M=0 C=1 T=Unknown S=0 F=0 B=0 BK=0 P=360 Name=typename L=18 PPK=2 FakeLParens=1/ FakeRParens=0 II=0x1e561a6bea0 Text='typename'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=263 Name=identifier L=20 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561aa0598 Text='T'
 M=0 C=0 T=Unknown S=0 F=0 B=0 BK=0 P=261 Name=comma L=21 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text=','
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=261 Name=enum L=26 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561a6b230 Text='enum'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=263 Name=identifier L=28 PPK=2 FakeLParens= FakeRParens=1 II=0x1e561aa05c8 Text='B'
 M=0 C=0 T=TemplateCloser S=0 F=0 B=0 BK=0 P=270 Name=greater L=29 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='>'
 M=1 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=30 Name=class L=109 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561a6ba28 Text='class'

 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=21 Name=identifier L=111 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561aa05f8 Text='D'
 M=0 C=0 T=DictLiteral S=1 F=0 B=0 BK=1 P=23 Name=l_brace L=113 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='{'
^^^^^^^^^^^^^^^^^^^^^^^

 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=59 Name=public L=120 PPK=2 FakeLParens=2/0/ FakeRParens=0 II=0x1e561a6bcf8 Text='public'
 M=0 C=0 T=DictLiteral S=1 F=0 B=0 BK=0 P=43 Name=colon L=122 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text=':'
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=43 Name=static L=129 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561a6b540 Text='static'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=43 Name=constexpr L=139 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561a61b38 Text='constexpr'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=43 Name=identifier L=141 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561aa0628 Text='A'
 M=0 C=1 T=StartOfName S=1 F=0 B=0 BK=0 P=240 Name=identifier L=143 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561aa0658 Text='g'
 M=0 C=0 T=BinaryOperator S=1 F=0 B=0 BK=0 P=42 Name=equal L=145 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='='
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=42 Name=numeric_constant L=147 PPK=2 FakeLParens= FakeRParens=1 II=0x0 Text='1'
 M=0 C=0 T=Unknown S=0 F=0 B=0 BK=0 P=43 Name=semi L=148 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text=';'
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=40 Name=static L=155 PPK=2 FakeLParens=2/ FakeRParens=0 II=0x1e561a6b540 Text='static'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=43 Name=constexpr L=165 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561a61b38 Text='constexpr'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=43 Name=identifier L=167 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561aa05c8 Text='B'
 M=0 C=1 T=StartOfName S=1 F=0 B=0 BK=0 P=240 Name=identifier L=169 PPK=2 FakeLParens= FakeRParens=0 II=0x1e561aa0688 Text='h'
 M=0 C=0 T=BinaryOperator S=1 F=0 B=0 BK=0 P=42 Name=equal L=171 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='='
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=42 Name=numeric_constant L=173 PPK=2 FakeLParens= FakeRParens=1 II=0x0 Text='2'
 M=0 C=0 T=Unknown S=0 F=0 B=0 BK=0 P=43 Name=semi L=174 PPK=2 FakeLParens= FakeRParens=1 II=0x0 Text=';'
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=40 Name=r_brace L=176 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='}'

if I change the enum to class

template <typename T, class B>
class D {
 public:
  static constexpr A g = 1;
  static constexpr B h = 2;
}

Then the { is no longer seen as a DictLiteral

 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=0 Name=template L=8 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef87d88 Text='template'
 M=0 C=0 T=TemplateOpener S=1 F=0 B=0 BK=0 P=30 Name=less L=10 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='<'
 M=0 C=1 T=Unknown S=0 F=0 B=0 BK=0 P=360 Name=typename L=18 PPK=2 FakeLParens=1/ FakeRParens=0 II=0x1961ef87e80 Text='typename'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=263 Name=identifier L=20 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef82388 Text='T'
 M=0 C=0 T=Unknown S=0 F=0 B=0 BK=0 P=261 Name=comma L=21 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text=','
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=261 Name=class L=27 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef87a08 Text='class'
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=5260 Name=identifier L=29 PPK=2 FakeLParens= FakeRParens=1 II=0x1961ef823b8 Text='B'
 M=0 C=0 T=TemplateCloser S=0 F=0 B=0 BK=0 P=270 Name=greater L=30 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='>'
 M=1 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=30 Name=class L=110 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef87a08 Text='class'
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=5020 Name=identifier L=112 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef823e8 Text='D'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=1 P=23 Name=l_brace L=114 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='{'
----
AnnotatedTokens(L=1):
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=0 Name=public L=6 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef87cd8 Text='public'
 M=0 C=1 T=InheritanceColon S=0 F=0 B=0 BK=0 P=23 Name=colon L=7 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text=':'
----
AnnotatedTokens(L=1):
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=0 Name=static L=6 PPK=2 FakeLParens=2/ FakeRParens=0 II=0x1961ef87520 Text='static'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=23 Name=constexpr L=16 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef43278 Text='constexpr'
 M=0 C=0 T=Unknown S=1 F=0 B=0 BK=0 P=23 Name=identifier L=18 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef82418 Text='A'
 M=0 C=1 T=StartOfName S=1 F=0 B=0 BK=0 P=220 Name=identifier L=20 PPK=2 FakeLParens= FakeRParens=0 II=0x1961ef82448 Text='g'
 M=0 C=0 T=BinaryOperator S=1 F=0 B=0 BK=0 P=22 Name=equal L=22 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text='='
 M=0 C=1 T=Unknown S=1 F=0 B=0 BK=0 P=22 Name=numeric_constant L=24 PPK=2 FakeLParens= FakeRParens=1 II=0x0 Text='1'
 M=0 C=0 T=Unknown S=0 F=0 B=0 BK=0 P=23 Name=semi L=25 PPK=2 FakeLParens= FakeRParens=0 II=0x0 Text=';'

Ultimately the constexpr or static do not get involved

As even this case is still incorrect

template <class A, enum B>
class D {
  public : int a;
}
Quuxplusone commented 3 years ago

You are of course correct about mismatched braces. I must have slipped during simplification of my code. I am glad that you are reproducing it anyway.

Quuxplusone commented 3 years ago
This is caused by the following, we don't know how to handle enum if its not
the first template argument

case tok::kw_enum:
      // Ignore if this is part of "template <enum ...".
      if (Previous && Previous->is(tok::less)) {
        nextToken();
        break;
      }

      // parseEnum falls through and does not yet add an unwrapped line as an
      // enum definition can start a structural element.
      if (!parseEnum())
        break;
      // This only applies for C++.
      if (!Style.isCpp()) {
        addUnwrappedLine();
        return;
      }
      break;