Page MenuHomePhabricator

[clang][ASTImporter] Generic attribute import handling (first step).

Authored by balazske on Sep 10 2021, 9:04 AM.



Import of Attr objects was incomplete in ASTImporter.
This change introduces support for a generic way of importing an attribute.
For an usage example import of the attribute AssertCapability is
added to ASTImporter.
Updating the old attribute import code and adding new attributes or extending
the generic functions (if needed) is future work.

Diff Detail

Event Timeline

balazske created this revision.Sep 10 2021, 9:04 AM
balazske requested review of this revision.Sep 10 2021, 9:04 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 10 2021, 9:04 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

Thanks, nice work! I like the direction, however, I'd like to ask comments from @teemperor .


What's the reason of moving this hunk?


Why can't we use importChecked here?


Could you please remove this comment?


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?

shafik added inline comments.Sep 13 2021, 9:48 AM

Looks like left over unused code?


@martong the ASTImporter file is quite large as it is and I think it makes sense to have AttrImporter but perhaps it would help long-term maintainability to split it out into its own source file? What do you think?

martong added inline comments.Sep 13 2021, 11:44 AM

Yes, good idea, I agree. Although, I wouldn't insist to do that in this patch, a following patch is okay for me.

After all, it would make sense to split ASTNodeImporter into it's own implementation file. Or, even better, we could put Visit*Type, Visit*Decl and Visit*Stmt into separate files. Other than that, the ASTImporterTest.cpp test file compiles painfully slow, so that is among my TODOs for a while to split that up as well.

balazske added inline comments.Sep 14 2021, 2:44 AM

This is moved into the public section. Other such functions are public already.


For Identifier* no error is possible and importChecked does not work (could be added to have uniform code).


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.)

martong added a subscriber: steakhal.

@steakhal, could you please take a look?

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.


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.


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?


Please fix this.


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.

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


I think you should be consistently using typename or class. I'm generally in favor of using typename though.


So, this accepts universal references, shouldn't we std::forward when we consume them?
If not, why do you use && ?


Why don't you initialize the variables directly? Same for the other variables. This way they could be const as well.


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.


Should we dump to the stderr?


<3 More!


An iterator range is just a pair of iterators, am I right?
We could still pass them by value.


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.

balazske updated this revision to Diff 373525.Sep 20 2021, 2:22 AM
balazske marked 9 inline comments as done.

Fixed review issues.
Added code comments.


The data returned by value is the one that is passed to the attribute constructor. It is in exact the same form, and for arrays this is a simple pointer to the array data. The array in the attribute has a size parameter too, this can be passed separately from this object.

One such "importer" is created for every attribute argument even if it is of an array type. For the array size no such object has to be created, only for the array data.


In this case AT is the element type of the array attribute argument, mostly Expr * but can be any other. The AT should mean "Argument Type". Now is is renamed to T because it is the only parameter, and every other place T is used too. I think it is not needed to make a static assert for every possible attribute argument type. The class can be still used incorrectly and theoretically attribute argument can be of any type, so the assert adds not much value.


Here the first parameter is really a class, the second not.


Probably we can have a specialization for exactly the case when the attribute has one parameter called "Args" that is of an array type. We need to check at how many attributes this is the case, probably it is only used at the thread safety part (relatively) many times.


Probably enough to pass by value but this should be not worse than that.

balazske added inline comments.Sep 20 2021, 2:30 AM

It would be good to have a "sink stream" that just discards the input. In this case it is not needed to allocate memory buffer, the text output of the dump is not used. ASTImporterTest has already many unneeded output.

steakhal accepted this revision.Sep 20 2021, 2:58 AM

I think I'm convinced.


llvm::nulls() returns such a stream.

This revision is now accepted and ready to land.Sep 20 2021, 2:58 AM
martong accepted this revision.Sep 21 2021, 2:24 AM

Look good! Thanks!

balazske updated this revision to Diff 373922.Sep 21 2021, 7:26 AM

Dump to 'llvm::nulls()'.

steakhal accepted this revision.Sep 21 2021, 7:48 AM
This revision was landed with ongoing or failed builds.Sep 22 2021, 1:00 AM
This revision was automatically updated to reflect the committed changes.