[PATCH] D43357: [Concepts] Function trailing requires clauses

Richard Smith - zygoloid via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sat Dec 14 16:33:30 PST 2019


rsmith added inline comments.


================
Comment at: clang/include/clang/Basic/DiagnosticParseKinds.td:179-180
 def err_unexpected_semi : Error<"unexpected ';' before %0">;
+def err_expected_primary_got_unary : Error<
+  "expected primary expression before %0; did you forget parentheses?">;
+def note_potential_bin_op_in_constraint_logical_or : Note<
----------------
I think the "did you forget parentheses?" part here may be irritating to users who didn't know they needed parentheses at all -- it may be read as patronizing by some. Can we rephrase as "parentheses are required around a top-level unary %0 expression in a requires clause" or something like that?


================
Comment at: clang/include/clang/Basic/DiagnosticSemaKinds.td:2515
+  "'%0' in the two declarations is not considered equivalent - move it to a "
+  "concept and reference it from here:">;
+def note_ambiguous_atomic_constraints_second : Note<"and here">;
----------------
Don't use a colon to indicate a location. Diagnostics are formatted in many different ways and this won't always make sense. Also, where possible, don't pretty-print expressions in diagnostics; underline the source range instead.


================
Comment at: clang/include/clang/Basic/DiagnosticSemaKinds.td:2516
+  "concept and reference it from here:">;
+def note_ambiguous_atomic_constraints_second : Note<"and here">;
 
----------------
Similarly, this note presentation won't always make sense. Can we somehow rephrase these notes so they're more presenting the facts and less telling the user what to do?


================
Comment at: clang/include/clang/Basic/DiagnosticSemaKinds.td:3886-3895
+def note_ovl_candidate_constraints_not_satisfied : Note<
+    "candidate %select{function|function|constructor|"
+    "function|function|constructor|"
+    "constructor (the implicit default constructor)|"
+    "constructor (the implicit copy constructor)|"
+    "constructor (the implicit move constructor)|"
+    "function (the implicit copy assignment operator)|"
----------------
Don't repeat this `%select`; use `%sub{select_ovl_candidate_kind}` instead. (The enum and the appropriate `%select` have already changed at least twice since this was copy-pasted...)


================
Comment at: clang/include/clang/Parse/Parser.h:1652
                                         prec::Level MinPrec);
-  ExprResult ParseCastExpression(bool isUnaryExpression,
+  /// CastParseOption - Control what ParseCastExpression will parse.
+  enum CastParseOption {
----------------
Don't repeat the name of the entity in the doc comment. (This is an old style that we're phasing out; new code shouldn't do it.)


================
Comment at: clang/include/clang/Parse/Parser.h:1653
+  /// CastParseOption - Control what ParseCastExpression will parse.
+  enum CastParseOption {
+    AnyCastExpr = 0,
----------------
We would usually call this sort of enumeration `SomethingKind` not `SomethingOption`.


================
Comment at: clang/include/clang/Parse/Parser.h:1658
+  };
+  ExprResult ParseCastExpression(CastParseOption ExprType,
                                  bool isAddressOfOperand,
----------------
Please don't use `Type` as the name of something that's not a language-level type.


================
Comment at: clang/include/clang/Parse/Parser.h:2700
+  void InitCXXThisScopeForDeclaratorIfRelevant(const Declarator &D,
+      const DeclSpec &DS, llvm::Optional<Sema::CXXThisScopeRAII> &ThisScope);
   bool ParseRefQualifier(bool &RefQualifierIsLValueRef,
----------------
Line-wrapped parameters should start on the same column as the first parameter.


================
Comment at: clang/lib/Parse/ParseDecl.cpp:2068-2069
 
   if (ParseAsmAttributesAfterDeclarator(D))
     return nullptr;
 
----------------
We should check with GCC to see which side of the requires-clause they expect this.

For the second and subsequent declarations, we expect the asm label before the requires clause; here we parse the asm label after the requires clause.


================
Comment at: clang/lib/Parse/ParseDecl.cpp:2257-2258
+  //        declarator requires-clause
+  if (Tok.is(tok::kw_requires))
+    ParseTrailingRequiresClause(D);
+
----------------
We already parsed this for the first declarator in the group. Do we accidentally permit two requires clauses on the first declarator?


================
Comment at: clang/lib/Parse/ParseDeclCXX.cpp:3799-3810
+    if (D.isFunctionDeclarator()) {
+      auto &FTI = D.getFunctionTypeInfo();
+      if (FTI.Params)
+        for (auto &Param : ArrayRef<DeclaratorChunk::ParamInfo>(FTI.Params,
+                                                                FTI.NumParams)){
+          auto *ParamDecl = cast<NamedDecl>(Param.Param);
+          if (ParamDecl->getIdentifier())
----------------
This scope-building code should be in `Sema`, not in the parser. (Consider adding an `ActOnStartTrailingRequiresClause` / `ActOnFinishTrailingRequiresClause` pair.)


================
Comment at: clang/lib/Parse/ParseDeclCXX.cpp:3801
+      auto &FTI = D.getFunctionTypeInfo();
+      if (FTI.Params)
+        for (auto &Param : ArrayRef<DeclaratorChunk::ParamInfo>(FTI.Params,
----------------
Add braces for this multi-line `if`.


================
Comment at: clang/lib/Parse/ParseDeclCXX.cpp:3825
+  if (TrailingRequiresClause.isInvalid())
+    SkipUntil({tok::equal, tok::l_brace, tok::arrow, tok::kw_try, tok::comma},
+              StopAtSemi | StopBeforeMatch);
----------------
Also `tok::colon` for constructors.


================
Comment at: clang/lib/Parse/ParseExpr.cpp:349-350
+  if (Tok.is(tok::l_paren) &&
+      isa<UnresolvedLookupExpr>(RightMostExpr) &&
+      RightMostExpr->isTypeDependent()) {
+    // We're facing one of the following cases:
----------------
The parser shouldn't be encoding this kind of semantic knowledge. Please move this to `Sema`. (This is also not really a very general way to detect a function-like name: checking for an expression whose type is a function type or OverloadType would catch more cases.)


================
Comment at: clang/lib/Parse/ParseExpr.cpp:354
+    // template<typename> void foo() requires func<T>(
+    // In the first case, '(' cannot start a declaration, and in the second,
+    // '(' cannot follow the requires-clause in a function-definition nor in
----------------
I don't think this is true. Consider:

```
struct A {
  template<typename T> requires X<T>
  (A)() {}
};
```

For a trailing requires clause, we can be much more aggressive with our error detection here, though, and in that case perhaps we can unconditionally treat a trailing `(` as a function call.


================
Comment at: clang/lib/Parse/ParseExpr.cpp:901
+      if (Tok.is(tok::annot_typename))
+        Diag(Tok, diag::err_expected_primary_got_unary) << "type name";
+      else
----------------
Do not hardcode English strings into diagnostic arguments. Use a `%select` or a different diagnostic instead.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D43357/new/

https://reviews.llvm.org/D43357





More information about the cfe-commits mailing list