Skip to content

Allow tag-based API notes on anonymous tag decls with typedef names #110768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 2, 2024

Conversation

DougGregor
Copy link
Contributor

It is common practice in C to declare anonymous tags that are immediately given a typedef name, e.g.,

typedef enum { ... } MyType;

At present, one can only express API notes on the typedef. However, that excludes the possibility of tag-specific notes like EnumExtensibility. For these anonymous declarations, process API notes using the typedef name as the tag name, so that one can add API notes to MyType via the Tags section.

It is common practice in C to declare anonymous tags that are
immediately given a typedef name, e.g.,

    typedef enum { ... } MyType;

At present, one can only express API notes on the typedef. However, that
excludes the possibility of tag-specific notes like EnumExtensibility.
For these anonymous declarations, process API notes using the typedef
name as the tag name, so that one can add API notes to `MyType` via
the `Tags` section.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 2, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 2, 2024

@llvm/pr-subscribers-clang

Author: Doug Gregor (DougGregor)

Changes

It is common practice in C to declare anonymous tags that are immediately given a typedef name, e.g.,

typedef enum { ... } MyType;

At present, one can only express API notes on the typedef. However, that excludes the possibility of tag-specific notes like EnumExtensibility. For these anonymous declarations, process API notes using the typedef name as the tag name, so that one can add API notes to MyType via the Tags section.


Full diff: https://github.com/llvm/llvm-project/pull/110768.diff

6 Files Affected:

  • (modified) clang/lib/Sema/SemaAPINotes.cpp (+9-1)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+3)
  • (modified) clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.apinotes (+2)
  • (modified) clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.h (+4)
  • (modified) clang/test/APINotes/types.m (+3)
  • (modified) clang/test/APINotes/yaml-roundtrip-2.test (+1-1)
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index d0236d08c98e68..ec43a0def9c1e6 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -913,7 +913,15 @@ void Sema::ProcessAPINotes(Decl *D) {
 
     // Tags
     if (auto Tag = dyn_cast<TagDecl>(D)) {
-      std::string LookupName = Tag->getName().str();
+      // Determine the name of the entity to search for. If this is an
+      // anonymous tag that gets its linked name from a typedef, look for the
+      // typedef name. This allows tag-specific information to be added
+      // to the declaration.
+      std::string LookupName;
+      if (auto typedefName = Tag->getTypedefNameForAnonDecl())
+        LookupName = typedefName->getName().str();
+      else
+        LookupName = Tag->getName().str();
 
       // Use the source location to discern if this Tag is an OPTIONS macro.
       // For now we would like to limit this trick of looking up the APINote tag
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 0e536f71a2f70d..92c85313d67cdd 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4974,6 +4974,9 @@ void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec,
 
   // Otherwise, set this as the anon-decl typedef for the tag.
   TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD);
+
+  // Now that we have a name for the tag, process API notes again.
+  ProcessAPINotes(TagFromDeclSpec);
 }
 
 static unsigned GetDiagnosticTypeSpecifierID(const DeclSpec &DS) {
diff --git a/clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.apinotes b/clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.apinotes
index ef6e44c51c21c7..f51811354eb00b 100644
--- a/clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.apinotes
+++ b/clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.apinotes
@@ -46,3 +46,5 @@ Tags:
     SwiftName:       SuccessfullyRenamedA
   - Name:            RenamedAgainInAPINotesB
     SwiftName:       SuccessfullyRenamedB
+  - Name:            AnonEnumWithTypedefName
+    SwiftName:       SuccessfullyRenamedC
diff --git a/clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.h b/clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.h
index bd73926e9d6af4..7342c3f83141bb 100644
--- a/clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.h
+++ b/clang/test/APINotes/Inputs/Frameworks/SimpleKit.framework/Headers/SimpleKit.h
@@ -27,3 +27,7 @@ void *getCFAuditedToNone_DUMP(void);
 - (id)getOwnedToUnowned __attribute__((__ns_returns_retained__));
 - (id)getUnownedToOwned __attribute__((__ns_returns_not_retained__));
 @end
+
+typedef enum {
+  kConstantInAnonEnum
+} AnonEnumWithTypedefName;
diff --git a/clang/test/APINotes/types.m b/clang/test/APINotes/types.m
index 133d504713d76c..752f1026432844 100644
--- a/clang/test/APINotes/types.m
+++ b/clang/test/APINotes/types.m
@@ -7,6 +7,9 @@
 
 // CHECK: struct __attribute__((swift_name("SuccessfullyRenamedA"))) RenamedAgainInAPINotesA {
 // CHECK: struct __attribute__((swift_name("SuccessfullyRenamedB"))) RenamedAgainInAPINotesB {
+// CHECK: typedef enum __attribute__((swift_name("SuccessfullyRenamedC"))) {
+// CHECK-NEXT: kConstantInAnonEnum
+// CHECK-NEXT: } AnonEnumWithTypedefName
 
 void test(OverriddenTypes *overridden) {
   int *ip1 = global_int_ptr; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'double (*)(int, int)'}}
diff --git a/clang/test/APINotes/yaml-roundtrip-2.test b/clang/test/APINotes/yaml-roundtrip-2.test
index b0b777b595060d..63717bda7c0991 100644
--- a/clang/test/APINotes/yaml-roundtrip-2.test
+++ b/clang/test/APINotes/yaml-roundtrip-2.test
@@ -7,5 +7,5 @@ REQUIRES: shell
 
 We expect only the document markers to be emitted
 
-CHECK: 50d
+CHECK: 52d
 CHECK: 1d

@egorzhdan egorzhdan merged commit 694fd1f into llvm:main Oct 2, 2024
11 checks passed
@DougGregor DougGregor deleted the api-notes-anonymous-tag-decls branch October 2, 2024 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants