[PATCH] D134286: [C2x] implement typeof and typeof_unqual

Aaron Ballman via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 20 13:15:39 PDT 2022


aaron.ballman marked 13 inline comments as done.
aaron.ballman added a comment.

In D134286#3803077 <https://reviews.llvm.org/D134286#3803077>, @erichkeane wrote:

> I'm on the fence about re-using the same nodes for `typeof` and `typeof_unqual`.  However, I have a preference to stop shuffling a bool around everywhere as parameters, and would like an enum (even if we store it as a bitfield : 1).  Something like:
>
>   enum class TypeofKind {
>          Typeof, TypeofUnqual };
>
> I think improves readability in a bunch of places, AND gives us less work to do if we need to extend this node in the future.

I'm happy to switch to an enum for this. I don't think it makes a whole lot of sense to add additional types for `typeof_unqual` support though. Using inheritance would be a bit risky (someone may accidentally use a `typeof_unqual` type as a `typeof`), and there's only one bit of difference between the two types.



================
Comment at: clang/include/clang/AST/ASTContext.h:1717
 
   /// GCC extension.
+  QualType getTypeOfExprType(Expr *E, bool IsUnqual) const;
----------------
shafik wrote:
> I guess these are not purely extensions anymore?
Good catch!


================
Comment at: clang/include/clang/AST/Type.h:4537
   Expr *TOExpr;
+  bool IsUnqual;
 
----------------
mizvekov wrote:
> You can use the Type Bitfields in order to avoid bumping the size of the node.
> 
Good call!


================
Comment at: clang/include/clang/AST/Type.h:4542
 
-  TypeOfExprType(Expr *E, QualType can = QualType());
+  TypeOfExprType(Expr *E, bool IsUnqual, QualType Can = QualType());
 
----------------
erichkeane wrote:
> This constructor is smelly.... Am I to guess this does something like, "if E, type is the type of this, else it is the type passed in Can?"
No, it's more that `E` holds the type and `Can` holds the canonical type, which can sometimes be different than the type of `E` in the case of dependent typeof expressions. See `ASTContext::getTypeOfExprType()` for the interesting use.


================
Comment at: clang/include/clang/AST/Type.h:4601
+    QualType QT = getUnderlyingType();
+    return IsUnqual ? QT.getTypeofUnqualType() : QT;
+  }
----------------
mizvekov wrote:
> shafik wrote:
> > It is interesting that you do `getTypeofUnqualType` in the constructor and then you have to do it again when desuguring. Is this tested in the tests?
> The constructor takes the canonical type, while this preserves the unmodified type (which can be accessed through getUnderlyingType).
Yup, this is covered in the tests. `desugar()` gets called as part of type merging, and the canonical type is used when printing `aka` information.


================
Comment at: clang/lib/AST/Type.cpp:3502
+  // We strip all qualifier-like attributes as well.
+  if (const auto *AT =
+          dyn_cast_if_present<AttributedType>(Ret.getTypePtrOrNull());
----------------
erichkeane wrote:
> In what situation is getTypePtrOrNull required here?  I would imagine that the 'isNull' check above should make sure we aren't in a situation where 'Ret' could be 'null' here?  Same with the 'if_present'.
This was a hold over from before I had the `isNull()` check above, so I've fixed this up.


================
Comment at: clang/lib/Lex/Preprocessor.cpp:61
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/Capacity.h"
----------------
erichkeane wrote:
> Oh?
Wth? No idea how that got here, but it's gone now.


================
Comment at: clang/lib/Parse/ParseDecl.cpp:7463
   SourceLocation StartLoc = ConsumeToken();
-
-  const bool hasParens = Tok.is(tok::l_paren);
+  bool HasParens = Tok.is(tok::l_paren);
 
----------------
erichkeane wrote:
> Should it be an error to `!HasParens` if `IsUnqual`.
I don't think we can get here in C2x mode, and `typeof_unqual` is not exposed outside of that mode. We've got test coverage for this (in C2x):
```
typeof 0 int i = 12;         // expected-error {{expected '(' after 'typeof'}} expected-error {{expected identifier or '('}}
typeof 0 j = 12;             // expected-error {{expected '(' after 'typeof'}} expected-error {{expected identifier or '('}}
typeof_unqual 0 k = 12;      // expected-error {{expected '(' after 'typeof_unqual'}} expected-error {{expected identifier or '('}}
typeof_unqual 0 int l = 12;  // expected-error {{expected '(' after 'typeof_unqual'}} expected-error {{expected identifier or '('}}
```



================
Comment at: clang/lib/Sema/SemaType.cpp:9137
+    Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield)
+        << (IsUnqual ? 3 : 2);
 
----------------
erichkeane wrote:
> `(IsUnqual + 2)` maybe?  Or perhaps too cute.
LoL far too cute, but this will change now that I'm using an enum more.


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

https://reviews.llvm.org/D134286



More information about the cfe-commits mailing list