steakhal added a comment.

I like the adapter layer idea. However, I agree with @martong that it should be 
more 'abstract' ~ terse.
It's remarkable how compact the test is. Good job.



================
Comment at: clang/lib/AST/ASTImporter.cpp:8417-8418
+template <typename T> struct AttrArgImporter {
+  AttrArgImporter<T>(const AttrArgImporter<T> &) = delete;
+  AttrArgImporter<T>(AttrArgImporter<T> &&) = default;
+
----------------
What about the rest of the special member functions like assignment operators?

All the rest of the code mentions this template parameter using the `AT` name.  
Could you please consolidate this? It would make it more readable.


================
Comment at: clang/lib/AST/ASTImporter.cpp:8425
+
+  const T &value() { return To; }
+};
----------------
So, the `value()` sometimes returns const ref, and other times it returns a 
mutable raw pointer...

I suspect, attribute constructors expect simple reference arguments and 
pointers for lists. And this is why it behaves like this. Am I right about this?


================
Comment at: clang/lib/AST/ASTImporter.cpp:8439
+      return;
+    } else {
+      To.reserve(ArraySize);
----------------
Please fix this.


================
Comment at: clang/lib/AST/ASTImporter.cpp:8460-8462
+  template <class AT>
+  AttrArgArrayImporter<AT>
+  importArrayArg(const llvm::iterator_range<AT *> &From, unsigned ArraySize) {
----------------
The name `AT` suggests to me that you expect the template type parameter to be 
a subtype of `class Attr`. However, I suspect it's not always the case.
For example in case of the `OwnershipAttr` the `args()` returns a sequence of 
`ParamIdx*` objects. So, in that sense, the `AT` name is not properly justified.

Restricting template parameter types makes the code cleaner, so I would suggest 
introducing a metafunction, that you could use in a `static_assert` that you 
could use to check this requirement as the first instruction in the function.

```lang=C++
template <typename T>
constexpr static bool AttrOrParamIdx = std::is_base_of<Attr, T>::value || 
std::is_same_v<T, ParamIdx>;

static_assert(AttrOrParamIdx<T>);
```


================
Comment at: clang/lib/AST/ASTImporter.cpp:8466
+
+  template <class T, typename... Arg>
+  Expected<Attr *> createImportedAttr(const T *FromAttr, Arg &&...ImportedArg) 
{
----------------
I think you should be consistently using `typename` or `class`. I'm generally 
in favor of using `typename` though.


================
Comment at: clang/lib/AST/ASTImporter.cpp:8467
+  template <class T, typename... Arg>
+  Expected<Attr *> createImportedAttr(const T *FromAttr, Arg &&...ImportedArg) 
{
+    const IdentifierInfo *ToAttrName;
----------------
So, this accepts universal references, shouldn't we `std::forward` when we 
consume them?
If not, why do you use `&&` ?


================
Comment at: clang/lib/AST/ASTImporter.cpp:8473-8474
+
+    ToAttrName = Importer.Import(FromAttr->getAttrName());
+    ToScopeName = Importer.Import(FromAttr->getScopeName());
+    ToAttrRange = NImporter.importChecked(Err, FromAttr->getRange());
----------------
balazske wrote:
> martong wrote:
> > Why can't we use `importChecked` here?
> For `Identifier*` no error is possible and `importChecked` does not work 
> (could be added to have uniform code).
Why don't you initialize the variables directly? Same for the other variables. 
This way they could be const as well.


================
Comment at: clang/lib/AST/ASTImporter.cpp:8547-8548
+    Expected<Attr *> ToAttrOrErr = AI.createImportedAttr(
+        From, AI.importArrayArg(From->args(), From->args_size()).value(),
+        From->args_size());
+    if (ToAttrOrErr)
----------------
balazske wrote:
> martong wrote:
> > Could we hide these arguments?
> > I mean we probably need a higher abstraction, something like
> > ```
> > Expected<Attr *> ToAttrOrErr = AI.createImportedAttr(From);
> > ```
> > should be sufficient, isn't it. We do want to import all arguments of all 
> > kind of attributes, don't we?
> It should be possible to pass every kind of needed arguments (after it is 
> imported) to the constructor of the newly created `Attr` object. The problem 
> is solved here by the `AttrArgImporter` that imports the object and can store 
> it in a temporary value until it is passed to the constructor. The temporary 
> value is important if an array is imported. To import the array the size must 
> be passed to the array importer before, and the size must be passed to the 
> constructor of the `Attr` too, therefore it exists 2 times in the code. An 
> `AttrArgImporter` can provide only one value to the constructor of the new 
> `Attr` object. (Probably other solution is possible with `std::tuple` and 
> `std::apply` but not sure if it is better.)
What about having two implementations. One for any T that has `args()` and one 
for anything else and using SFINAE choosing the right one.
In this context, we should have the appropriate dynamic type, so by using 
template type deduction on `From` could achieve this dispatch.

Internally it could do the `AI.importArrayArg(From->args(), 
From->args_size()).value()` for the `args()` case.
WDYT?


================
Comment at: clang/unittests/AST/ASTImporterTest.cpp:6414
+    // Verify that dump does not crash because invalid data.
+    ToD->dump();
+
----------------
Should we dump to the `stderr`?


================
Comment at: clang/unittests/AST/ASTImporterTest.cpp:6442-6443
+  void importAttr(const char *Code, AT *&FromAttr, AT *&ToAttr) {
+    static_assert(std::is_base_of<Attr, AT>::value, "AT should be an Attr");
+    static_assert(std::is_base_of<Decl, DT>::value, "DT should be a Decl");
+
----------------
<3 More!


================
Comment at: clang/unittests/AST/ASTImporterTest.cpp:6467-6468
+  template <class T>
+  void checkImportVariadicArg(const llvm::iterator_range<T **> &From,
+                              const llvm::iterator_range<T **> &To) {
+    for (auto FromI = From.begin(), ToI = To.begin(); FromI != From.end();
----------------
An iterator range is just a pair of iterators, am I right?
We could still pass them by value.


================
Comment at: clang/unittests/AST/ASTImporterTest.cpp:6549-6551
+      R"(
+      void test(int A1, int A2) __attribute__((assert_capability(A1, A2)));
+      )",
----------------
You could probably use the regular `"void test(int A1, int A2) 
__attribute__((assert_capability(A1, A2)));"` string literal. It would still 
fit in the line and would consume only a single line.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D109608

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to