This is an archive of the discontinued LLVM Phabricator instance.

[clang][pp] Handle attributes defined by plugin in __has_attribute
ClosedPublic

Authored by wanders on Feb 20 2023, 8:36 AM.

Details

Summary

When using attributes by plugins (both in clang and clang-tidy) the
preprocessor functions __has_attribute, __has_c_attribute,
__has_cpp_attribute still returned 0.

That problem is fixed by having the "hasAttribute" function also check
if any of the plugins provide that attribute.

This also adds C2x spelling to the example plugin for attributes so that
__has_c_attribute can be tested.

Diff Detail

Event Timeline

wanders created this revision.Feb 20 2023, 8:36 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 20 2023, 8:36 AM
Herald added a subscriber: jdoerfert. · View Herald Transcript
wanders requested review of this revision.Feb 20 2023, 8:36 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 20 2023, 8:36 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
wanders retitled this revision from [clang][pp] Handle attributes defined by plugin in __has_attribute r=aaron.ballman to [clang][pp] Handle attributes defined by plugin in __has_attribute.Feb 20 2023, 8:42 AM

This needs a release note. Otherwise I just have a preference for the 'is this spelling/syntax combo provided by this attribute' being in the plugin infrastructure. It DOES make me wonder however, what happens if TWO plugins provide a different 'true' answer for those?

clang/lib/Basic/Attributes.cpp
40

Ah, I see what you've done here. I guess that is OK on the other patch then.

46

I think this should be a property of the AttributePlugin type, where you send it the Syntax/Name and it checks to see if it is provided.

wanders added inline comments.Mar 1 2023, 3:33 AM
clang/lib/Basic/Attributes.cpp
46

Do you think I should do something like this?

(refactor based on mainline)

diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h
index f060564e6719..635580ac599b 100644
--- a/clang/include/clang/Sema/ParsedAttr.h
+++ b/clang/include/clang/Sema/ParsedAttr.h
@@ -98,6 +98,13 @@ protected:
 public:
   virtual ~ParsedAttrInfo() = default;
 
+  /// Check if this attribute can be spelled like this. Only used for plugin attributes
+  virtual bool hasSpelling(AttributeCommonInfo::Syntax Syntax, StringRef Name) {
+    return llvm::any_of(Spellings, [&] (const Spelling &S) {
+      return (S.Syntax == Syntax && S.NormalizedFullName == Name);
+    });
+  }
+
   /// Check if this attribute appertains to D, and issue a diagnostic if not.
   virtual bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr,
                                     const Decl *D) const {
diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp
index c1e39acb14ec..b53132d73d79 100644
--- a/clang/lib/Sema/ParsedAttr.cpp
+++ b/clang/lib/Sema/ParsedAttr.cpp
@@ -135,8 +135,7 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
     SyntaxUsed = AttributeCommonInfo::AS_Keyword;
 
   for (auto &Ptr : *PluginAttrInstances)
-    for (auto &S : Ptr->Spellings)
-      if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName)
+    if (Ptr->handlesSpelling(SyntaxUsed, FullName))
         return *Ptr;
 
   // If we failed to find a match then return a default ParsedAttrInfo.

Maybe not virtual as allowing plugins to handle attributes not in their Spellings array maybe is too flexible?

erichkeane added inline comments.Mar 6 2023, 6:35 AM
clang/lib/Basic/Attributes.cpp
46

Hi-
Sorry for the delayed response: you caught me out of the office.

Yes, that is what I meant. I would NOT make it virtual (for the reason you stated).

wanders updated this revision to Diff 504045.Mar 10 2023, 12:29 AM
wanders edited the summary of this revision. (Show Details)
wanders marked an inline comment as not done.
wanders marked 2 inline comments as done.Mar 10 2023, 12:39 AM

@erichkeane
Patch stack now updated to include a method extraction of hasSpelling, and releasenote added.

Looks like this doesn't compile pre-commit, though no idea if that is a patch-stack issue. Other than test, patch looks fine.

clang/test/Frontend/plugin-attribute-pp.cpp
2

This split-file thing is weird, don't do that. create 2 tests instead, OR Just use -x c and -x c++ to change languages (you can use a separate macro to get has_c and has_cpp_attribute right).

Looks like this doesn't compile pre-commit, though no idea if that is a patch-stack issue. Other than test, patch looks fine.

Yeah, when uploading the new commit the stack was disorganized. So the build probably started before I got around organizing the stack in correct order.

So hopefully clears up when I fix the test (clang-format and const thing)

clang/test/Frontend/plugin-attribute-pp.cpp
2

Right. That should be simpler. Will fix.

(it ended up this way because I first added a split to the existing plugin-attribute.cpp test with splits)

wanders updated this revision to Diff 504152.Mar 10 2023, 7:50 AM
erichkeane accepted this revision.Mar 10 2023, 7:54 AM

So here's a potential idea for future development: It isn't uncommon/untypical for an attribute to want to return something other than '1', for 'version' (usually an integral value representing a date). The standard attributes all do this. It might be worth looking into some infrastructure to do that.

This revision is now accepted and ready to land.Mar 10 2023, 7:54 AM

So here's a potential idea for future development: It isn't uncommon/untypical for an attribute to want to return something other than '1', for 'version' (usually an integral value representing a date). The standard attributes all do this. It might be worth looking into some infrastructure to do that.

Adding this to my list of things to look into. Thanks.

I see that D144403 in the stack is not accepted, is there anything I need to fix that I have missed?

My current plan after this is to look into making it possible to attach custom attributes to the AST nodes, and in the end use plugin-defined attributes in ASTMatchers.

So I'll probably be poking around in that area anyway.

My imaginary API for that is something like:

    /* find all calls to functions with my-attribute from functions without my-attribute
    Finder->addMatcher(callExpr(
				callee(
				       functionDecl(
						    hasAttr(MyAttribute)
						    )
				       )
				hasAncestor(
					    functionDecl(
							 unless(hasAttr(MyAttribute))
							 ).bind("containing-function")
					    )
				).bind("call"), this);

where "MyAttribute" is the plugin defined attribute.