[clang] 8c09352 - [libclang] Fix conversion from `StringRef` to `CXString`
Author: Egor Zhdan Date: 2022-08-31T17:39:45+01:00 New Revision: 8c0935238527622ba0a7e78e8a1ee2d36026961c URL: https://github.com/llvm/llvm-project/commit/8c0935238527622ba0a7e78e8a1ee2d36026961c DIFF: https://github.com/llvm/llvm-project/commit/8c0935238527622ba0a7e78e8a1ee2d36026961c.diff LOG: [libclang] Fix conversion from `StringRef` to `CXString` `CXString createRef(StringRef String)` used to return an invalid string when invoked with some empty strings: If a `StringRef` holds a non-nullptr pointer, for instance, pointing into contents of a larger string, and has a zero length, `createRef` previously returned the entire larger string, ignoring the fact that the actual string passed to it as a param is empty. This was discovered when invoking `c-index-test` to dump the contents of documentation comments, in case the comment contains an empty HTML attribute, such as `src=""`. Differential Revision: https://reviews.llvm.org/D133009 Added: Modified: clang/test/Index/comment-lots-of-unknown-commands.c clang/test/Index/comment-to-html-xml-conversion.cpp clang/tools/libclang/CXString.cpp Removed: diff --git a/clang/test/Index/comment-lots-of-unknown-commands.c b/clang/test/Index/comment-lots-of-unknown-commands.c index 119a34566094c..41a03d394488c 100644 --- a/clang/test/Index/comment-lots-of-unknown-commands.c +++ b/clang/test/Index/comment-lots-of-unknown-commands.c @@ -1,5 +1,7 @@ // RUN: c-index-test -test-load-source-reparse 1 local %s | FileCheck %s +// XFAIL: * + // See PR 21254. We had too few bits to encode command IDs so if you created // enough of them the ID codes would wrap around. This test creates commands up // to an ID of 258. Ideally we should check for large numbers, but that would diff --git a/clang/test/Index/comment-to-html-xml-conversion.cpp b/clang/test/Index/comment-to-html-xml-conversion.cpp index bba5cf8f0bf42..1fedd382365cf 100644 --- a/clang/test/Index/comment-to-html-xml-conversion.cpp +++ b/clang/test/Index/comment-to-html-xml-conversion.cpp @@ -744,6 +744,15 @@ void comment_to_html_conversion_37(); // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace) // CHECK-NEXT: (CXComment_InlineCommand CommandName=[anchor] RenderAnchor Arg[0]=A)))] +/// Aaa ccc +void comment_to_html_conversion_40(); + +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_40:{{.*}} FullCommentAsHTML=[ Aaa ccc] FullCommentAsXML=[comment_to_html_conversion_40c:@F@comment_to_html_conversion_40#void comment_to_html_conversion_40() Aaa ccc] +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT:(CXComment_FullComment +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ Aaa ccc]) +// CHECK-NEXT: (CXComment_HTMLStartTag Name=[img] Attrs: src=) /// Aaa. class comment_to_xml_conversion_01 { diff --git a/clang/tools/libclang/CXString.cpp b/clang/tools/libclang/CXString.cpp index 2754795f4a647..5e427957a1092 100644 --- a/clang/tools/libclang/CXString.cpp +++ b/clang/tools/libclang/CXString.cpp @@ -78,13 +78,22 @@ CXString createDup(const char *String) { } CXString createRef(StringRef String) { + if (!String.data()) +return createNull(); + + // If the string is empty, it might point to a position in another string + // while having zero length. Make sure we don't create a reference to the + // larger string. + if (String.empty()) +return createEmpty(); + // If the string is not nul-terminated, we have to make a copy. // FIXME: This is doing a one past end read, and should be removed! For memory // we don't manage, the API string can become unterminated at any time outside // our control. - if (!String.empty() && String.data()[String.size()] != 0) + if (String.data()[String.size()] != 0) return createDup(String); CXString Result; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 0cb0809 - [Clang][Comments] Parse `` in doc comments correctly
Author: Egor Zhdan Date: 2022-09-01T13:17:42+01:00 New Revision: 0cb08093365478224f2a58cece42527fb8e1199e URL: https://github.com/llvm/llvm-project/commit/0cb08093365478224f2a58cece42527fb8e1199e DIFF: https://github.com/llvm/llvm-project/commit/0cb08093365478224f2a58cece42527fb8e1199e.diff LOG: [Clang][Comments] Parse `` in doc comments correctly This is a valid HTML5 tag. Previously it triggered a Clang error (`HTML start tag prematurely ended, expected attribute name or '>'`) since Clang was treating `/>` as a text token. This was happening because after lexing the closing quote (`"`) the lexer state was reset to "Normal" while the tag was not actually closed yet: `>` was not yet parsed at that point. rdar://91464292 Differential Revision: https://reviews.llvm.org/D132932 Added: Modified: clang/lib/AST/CommentLexer.cpp clang/test/Index/comment-to-html-xml-conversion.cpp clang/test/Sema/warn-documentation.cpp Removed: diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp index 61ce8979f13f5..f0250fc9fd55e 100644 --- a/clang/lib/AST/CommentLexer.cpp +++ b/clang/lib/AST/CommentLexer.cpp @@ -701,7 +701,7 @@ void Lexer::lexHTMLStartTag(Token &T) { C = *BufferPtr; if (!isHTMLIdentifierStartingCharacter(C) && - C != '=' && C != '\"' && C != '\'' && C != '>') { + C != '=' && C != '\"' && C != '\'' && C != '>' && C != '/') { State = LS_Normal; return; } diff --git a/clang/test/Index/comment-to-html-xml-conversion.cpp b/clang/test/Index/comment-to-html-xml-conversion.cpp index 1fedd382365cf..ec49e5af31da1 100644 --- a/clang/test/Index/comment-to-html-xml-conversion.cpp +++ b/clang/test/Index/comment-to-html-xml-conversion.cpp @@ -744,6 +744,26 @@ void comment_to_html_conversion_37(); // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace) // CHECK-NEXT: (CXComment_InlineCommand CommandName=[anchor] RenderAnchor Arg[0]=A)))] +/// Aaa bbb +void comment_to_html_conversion_38(); + +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_38:{{.*}} FullCommentAsHTML=[ Aaa bbb] FullCommentAsXML=[comment_to_html_conversion_38c:@F@comment_to_html_conversion_38#void comment_to_html_conversion_38() Aaa bbb] +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT:(CXComment_FullComment +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ Aaa bbb]) +// CHECK-NEXT: (CXComment_HTMLStartTag Name=[img] SelfClosing) + +/// Aaa ccc +void comment_to_html_conversion_39(); + +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_39:{{.*}} FullCommentAsHTML=[ Aaa ccc] FullCommentAsXML=[comment_to_html_conversion_39c:@F@comment_to_html_conversion_39#void comment_to_html_conversion_39() Aaa ccc] +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT:(CXComment_FullComment +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ Aaa ccc]) +// CHECK-NEXT: (CXComment_HTMLStartTag Name=[img] SelfClosing) + /// Aaa ccc void comment_to_html_conversion_40(); @@ -754,6 +774,36 @@ void comment_to_html_conversion_40(); // CHECK-NEXT: (CXComment_Text Text=[ Aaa ccc]) // CHECK-NEXT: (CXComment_HTMLStartTag Name=[img] Attrs: src=) +/// Aaa ccc +void comment_to_html_conversion_41(); + +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_41:{{.*}} FullCommentAsHTML=[ Aaa ccc] FullCommentAsXML=[comment_to_html_conversion_41c:@F@comment_to_html_conversion_41#void comment_to_html_conversion_41() Aaa ccc] +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT:(CXComment_FullComment +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ Aaa ccc]) +// CHECK-NEXT: (CXComment_HTMLStartTag Name=[img] Attrs: src=path) + +/// Aaa ccc +void comment_to_html_conversion_42(); + +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_42:{{.*}} FullCommentAsHTML=[ Aaa ccc] FullCommentAsXML=[comment_to_html_conversion_42c:@F@comment_to_html_conversion_42#void comment_to_html_conversion_42() Aaa ccc] +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT:(CXComment_FullComment +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ Aaa ccc]) +// CHECK-NEXT: (CXComment_HTMLStartTag Name=[img] Attrs: src=path SelfClosing) + +/// Aaa ddd +void comment_to_html_conversion_43(); + +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_43:{{.*}} FullCommentAsHTML=[ Aaa ddd] FullCommentAsXML=[comment_to_html_conversion_43c:@F@comment_to_html_conversion_43#void comment_to_html_conversion_43() Aaa ddd] +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT:(CXComment_FullComment +//
[clang] 7c232b0 - [Clang][Comments] Fix `Index/comment-lots-of-unknown-commands.c`
Author: Egor Zhdan Date: 2022-09-02T12:34:38+01:00 New Revision: 7c232b0867209a8f487bbcabca9289e9ef313bef URL: https://github.com/llvm/llvm-project/commit/7c232b0867209a8f487bbcabca9289e9ef313bef DIFF: https://github.com/llvm/llvm-project/commit/7c232b0867209a8f487bbcabca9289e9ef313bef.diff LOG: [Clang][Comments] Fix `Index/comment-lots-of-unknown-commands.c` This re-enables a test after it was disabled in https://reviews.llvm.org/D133009. Fixes #57484. Differential Revision: https://reviews.llvm.org/D133105 Added: Modified: clang/test/Index/comment-lots-of-unknown-commands.c Removed: diff --git a/clang/test/Index/comment-lots-of-unknown-commands.c b/clang/test/Index/comment-lots-of-unknown-commands.c index 41a03d394488c..1de96762dc4ae 100644 --- a/clang/test/Index/comment-lots-of-unknown-commands.c +++ b/clang/test/Index/comment-lots-of-unknown-commands.c @@ -1,7 +1,5 @@ // RUN: c-index-test -test-load-source-reparse 1 local %s | FileCheck %s -// XFAIL: * - // See PR 21254. We had too few bits to encode command IDs so if you created // enough of them the ID codes would wrap around. This test creates commands up // to an ID of 258. Ideally we should check for large numbers, but that would @@ -37,7 +35,7 @@ @ei @oun @ou -@nl +@nlnl @ien @fr @en @@ -58,7 +56,7 @@ @fro @ast @ae -@nN +@nNnN @pc @tae @ws @@ -122,10 +120,10 @@ @an @de @tel -@nd -@dic +@ndnd +@dict @Lo -@il +@ilil @tle @axt @ba @@ -137,7 +135,7 @@ @ru @m @tG -@it +@itit @rh @G @rpc @@ -183,7 +181,7 @@ void f(); // CHECK: (CXComment_InlineCommand CommandName=[ei] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[oun] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[ou] RenderNormal HasTrailingNewline) -// CHECK: (CXComment_InlineCommand CommandName=[nl] RenderNormal HasTrailingNewline) +// CHECK: (CXComment_InlineCommand CommandName=[nlnl] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[ien] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[fr] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[en] RenderNormal HasTrailingNewline) @@ -204,7 +202,7 @@ void f(); // CHECK: (CXComment_InlineCommand CommandName=[fro] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[ast] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[ae] RenderNormal HasTrailingNewline) -// CHECK: (CXComment_InlineCommand CommandName=[nN] RenderNormal HasTrailingNewline) +// CHECK: (CXComment_InlineCommand CommandName=[nNnN] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[pc] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[tae] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[ws] RenderNormal HasTrailingNewline) @@ -268,10 +266,10 @@ void f(); // CHECK: (CXComment_InlineCommand CommandName=[an] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[de] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[tel] RenderNormal HasTrailingNewline) -// CHECK: (CXComment_InlineCommand CommandName=[nd] RenderNormal HasTrailingNewline) -// CHECK: (CXComment_InlineCommand CommandName=[dic] RenderNormal HasTrailingNewline) +// CHECK: (CXComment_InlineCommand CommandName=[ndnd] RenderNormal HasTrailingNewline) +// CHECK: (CXComment_InlineCommand CommandName=[dict] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[Lo] RenderNormal HasTrailingNewline) -// CHECK: (CXComment_InlineCommand CommandName=[il] RenderNormal HasTrailingNewline) +// CHECK: (CXComment_InlineCommand CommandName=[ilil] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[tle] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[axt] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[ba] RenderNormal HasTrailingNewline) @@ -283,7 +281,7 @@ void f(); // CHECK: (CXComment_InlineCommand CommandName=[ru] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[m] RenderNormal HasTrailingNewline) // CHECK: (CXComment_InlineCommand CommandName=[tG] RenderNormal HasTrailingNewline) -// CHECK: (CXComment_InlineCommand CommandName=[it] RenderNormal HasTrailingNewline) +// CHECK: (CXComment_InlineCommand CommandName=[itit] RenderNormal HasTrailingNewline) // CHECK:
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/71413 This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes >From f80d68edf0787821531c0f88d845b253703ef13e Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:41:19 + Subject: [PATCH 1/2] [APINotes] NFC: rename `StoredObjCSelector::NumPieces` This value actually represents a number of arguments the selector takes, not the number of identifiers. These will be different if the selector takes no arguments. --- clang/lib/APINotes/APINotesFormat.h | 6 +++--- clang/lib/APINotes/APINotesReader.cpp | 2 +- clang/lib/APINotes/APINotesWriter.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 5897b45d3796d0e..615314c46f09cac 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -247,7 +247,7 @@ using EnumConstantDataLayout = /// A stored Objective-C selector. struct StoredObjCSelector { - unsigned NumPieces; + unsigned NumArgs; llvm::SmallVector Identifiers; }; @@ -302,7 +302,7 @@ template <> struct DenseMapInfo { static unsigned getHashValue(const clang::api_notes::StoredObjCSelector &Selector) { -auto hash = llvm::hash_value(Selector.NumPieces); +auto hash = llvm::hash_value(Selector.NumArgs); hash = hash_combine(hash, Selector.Identifiers.size()); for (auto piece : Selector.Identifiers) hash = hash_combine(hash, static_cast(piece)); @@ -313,7 +313,7 @@ template <> struct DenseMapInfo { static bool isEqual(const clang::api_notes::StoredObjCSelector &LHS, const clang::api_notes::StoredObjCSelector &RHS) { -return LHS.NumPieces == RHS.NumPieces && LHS.Identifiers == RHS.Identifiers; +return LHS.NumArgs == RHS.NumArgs && LHS.Identifiers == RHS.Identifiers; } }; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index 2cbf5fd3bf50301..01177b9b1d04dde 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -421,7 +421,7 @@ class ObjCSelectorTableInfo { static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { internal_key_type Key; -Key.NumPieces = +Key.NumArgs = endian::readNext(Data); unsigned NumIdents = (Length - sizeof(uint16_t)) / sizeof(uint32_t); for (unsigned i = 0; i != NumIdents; ++i) { diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 770d78e22050c01..62a2ab1799913a1 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -823,7 +823,7 @@ class ObjCSelectorTableInfo { void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { llvm::support::endian::Writer writer(OS, llvm::endianness::little); -writer.write(Key.NumPieces); +writer.write(Key.NumArgs); for (auto Identifier : Key.Identifiers) writer.write(Identifier); } >From 903b4f72f914c64698a468adbba8a7af992bc9aa Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:45:11 + Subject: [PATCH 2/2] [APINotes] Upstream APINotes YAML compiler This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/APINotes/APINotesYAMLCompiler.h | 11 + clang/include/clang/APINotes/Types.h | 1 + clang/lib/APINotes/APINotesReader.cpp | 1 + clang/lib/APINotes/APINotesYAMLCompiler.cpp | 498 +- 4 files changed, 510 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/APINotes/APINotesYAMLCompiler.h b/clang/include/clang/APINotes/APINotesYAMLCompiler.h index 6098d0ee36fc477..9c24ed85b6a124a 100644 --- a/clang/include/clang/APINotes/APINotesYAMLCompiler.h +++ b/clang/include/clang/APINotes/APINotesYAMLCompiler.h @@ -10,14 +10,25 @@ #define LLVM_CLANG_APINOTES_APINOTESYAMLCOMPILER_H #include "llvm/ADT/StringRef.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +namespace clang { +class FileEntry; +} // namespace clang + namespace clang { namespace api_notes { /// Parses the APINotes YAML content and writes the representation back to the /// specified stream. This provides a means of testing the YAML processing of /// the APINotes format. bool parseAndDumpAPINotes(llvm::StringRef YI, llvm::raw_ostream &OS); + +/// Converts API notes from YAML format to binary format. +bool compileAPINotes(llvm::StringRef YAMLInput, const FileEntry *SourceFile, + llvm::raw_ostream &OS, + llvm::SourceMgr::DiagHandlerTy DiagHandler = nullptr, + void *DiagHandlerCtxt = nullptr); } // namesp
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/71413 >From f80d68edf0787821531c0f88d845b253703ef13e Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:41:19 + Subject: [PATCH 1/2] [APINotes] NFC: rename `StoredObjCSelector::NumPieces` This value actually represents a number of arguments the selector takes, not the number of identifiers. These will be different if the selector takes no arguments. --- clang/lib/APINotes/APINotesFormat.h | 6 +++--- clang/lib/APINotes/APINotesReader.cpp | 2 +- clang/lib/APINotes/APINotesWriter.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 5897b45d3796d0e..615314c46f09cac 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -247,7 +247,7 @@ using EnumConstantDataLayout = /// A stored Objective-C selector. struct StoredObjCSelector { - unsigned NumPieces; + unsigned NumArgs; llvm::SmallVector Identifiers; }; @@ -302,7 +302,7 @@ template <> struct DenseMapInfo { static unsigned getHashValue(const clang::api_notes::StoredObjCSelector &Selector) { -auto hash = llvm::hash_value(Selector.NumPieces); +auto hash = llvm::hash_value(Selector.NumArgs); hash = hash_combine(hash, Selector.Identifiers.size()); for (auto piece : Selector.Identifiers) hash = hash_combine(hash, static_cast(piece)); @@ -313,7 +313,7 @@ template <> struct DenseMapInfo { static bool isEqual(const clang::api_notes::StoredObjCSelector &LHS, const clang::api_notes::StoredObjCSelector &RHS) { -return LHS.NumPieces == RHS.NumPieces && LHS.Identifiers == RHS.Identifiers; +return LHS.NumArgs == RHS.NumArgs && LHS.Identifiers == RHS.Identifiers; } }; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index 2cbf5fd3bf50301..01177b9b1d04dde 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -421,7 +421,7 @@ class ObjCSelectorTableInfo { static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { internal_key_type Key; -Key.NumPieces = +Key.NumArgs = endian::readNext(Data); unsigned NumIdents = (Length - sizeof(uint16_t)) / sizeof(uint32_t); for (unsigned i = 0; i != NumIdents; ++i) { diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 770d78e22050c01..62a2ab1799913a1 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -823,7 +823,7 @@ class ObjCSelectorTableInfo { void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { llvm::support::endian::Writer writer(OS, llvm::endianness::little); -writer.write(Key.NumPieces); +writer.write(Key.NumArgs); for (auto Identifier : Key.Identifiers) writer.write(Identifier); } >From 912092a4a8a815b4b6b449842cb028f564f829f6 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:45:11 + Subject: [PATCH 2/2] [APINotes] Upstream APINotes YAML compiler This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/APINotes/APINotesYAMLCompiler.h | 11 + clang/include/clang/APINotes/Types.h | 1 + clang/lib/APINotes/APINotesReader.cpp | 1 + clang/lib/APINotes/APINotesYAMLCompiler.cpp | 479 +- 4 files changed, 491 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/APINotes/APINotesYAMLCompiler.h b/clang/include/clang/APINotes/APINotesYAMLCompiler.h index 6098d0ee36fc477..9c24ed85b6a124a 100644 --- a/clang/include/clang/APINotes/APINotesYAMLCompiler.h +++ b/clang/include/clang/APINotes/APINotesYAMLCompiler.h @@ -10,14 +10,25 @@ #define LLVM_CLANG_APINOTES_APINOTESYAMLCOMPILER_H #include "llvm/ADT/StringRef.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +namespace clang { +class FileEntry; +} // namespace clang + namespace clang { namespace api_notes { /// Parses the APINotes YAML content and writes the representation back to the /// specified stream. This provides a means of testing the YAML processing of /// the APINotes format. bool parseAndDumpAPINotes(llvm::StringRef YI, llvm::raw_ostream &OS); + +/// Converts API notes from YAML format to binary format. +bool compileAPINotes(llvm::StringRef YAMLInput, const FileEntry *SourceFile, + llvm::raw_ostream &OS, + llvm::SourceMgr::DiagHandlerTy DiagHandler = nullptr, + void *DiagHandlerCtxt = nullptr); } // namespace api_notes } // namespace clang diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index b74244bc8f1cbd3..79595abcf7d02d9 100644 --
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { egorzhdan wrote: Alright, done https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; egorzhdan wrote: Don't think there is a good reason, removed the return type https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } egorzhdan wrote: This underflows `offset`, but I simplified this bit of code another way by using `resize` https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, egorzhdan wrote: Makes sense, renamed it https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + +"is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef selectorRef; +selectorRef.NumArgs = !takesArguments ? 0 : a.size(); +selectorRef.Identifiers = a; + +// Translate the initializer info. +MInfo.DesignatedInit = TheMethod.DesignatedInit; +MInfo.RequiredInit = TheMethod.Required; +if (TheMethod.FactoryAsInit != FactoryAsInitKind::Infer) { + emitError("'Fact
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + +"is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef selectorRef; +selectorRef.NumArgs = !takesArguments ? 0 : a.size(); +selectorRef.Identifiers = a; + +// Translate the initializer info. +MInfo.DesignatedInit = TheMethod.DesignatedInit; +MInfo.RequiredInit = TheMethod.Required; +if (TheMethod.FactoryAsInit != FactoryAsInitKind::Infer) { + emitError("'Fact
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + +"is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef selectorRef; +selectorRef.NumArgs = !takesArguments ? 0 : a.size(); +selectorRef.Identifiers = a; + +// Translate the initializer info. +MInfo.DesignatedInit = TheMethod.DesignatedInit; +MInfo.RequiredInit = TheMethod.Required; +if (TheMethod.FactoryAsInit != FactoryAsInitKind::Infer) { + emitError("'Fact
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + +"is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef selectorRef; +selectorRef.NumArgs = !takesArguments ? 0 : a.size(); +selectorRef.Identifiers = a; + +// Translate the initializer info. +MInfo.DesignatedInit = TheMethod.DesignatedInit; +MInfo.RequiredInit = TheMethod.Required; +if (TheMethod.FactoryAsInit != FactoryAsInitKind::Infer) { + emitError("'Fact
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); egorzhdan wrote: This has two usages below https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} egorzhdan wrote: Looks better indeed, thanks! https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + +"is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef selectorRef; egorzhdan wrote: I renamed this to follow the upper-case conventions, would you prefer a different name? What does `seller` stand for? https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + +"is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef selectorRef; +selectorRef.NumArgs = !takesArguments ? 0 : a.size(); +selectorRef.Identifiers = a; + +// Translate the initializer info. +MInfo.DesignatedInit = TheMethod.DesignatedInit; +MInfo.RequiredInit = TheMethod.Required; +if (TheMethod.FactoryAsInit != FactoryAsInitKind::Infer) { + emitError("'Fact
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/71413 >From f80d68edf0787821531c0f88d845b253703ef13e Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:41:19 + Subject: [PATCH 1/2] [APINotes] NFC: rename `StoredObjCSelector::NumPieces` This value actually represents a number of arguments the selector takes, not the number of identifiers. These will be different if the selector takes no arguments. --- clang/lib/APINotes/APINotesFormat.h | 6 +++--- clang/lib/APINotes/APINotesReader.cpp | 2 +- clang/lib/APINotes/APINotesWriter.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 5897b45d3796d0e..615314c46f09cac 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -247,7 +247,7 @@ using EnumConstantDataLayout = /// A stored Objective-C selector. struct StoredObjCSelector { - unsigned NumPieces; + unsigned NumArgs; llvm::SmallVector Identifiers; }; @@ -302,7 +302,7 @@ template <> struct DenseMapInfo { static unsigned getHashValue(const clang::api_notes::StoredObjCSelector &Selector) { -auto hash = llvm::hash_value(Selector.NumPieces); +auto hash = llvm::hash_value(Selector.NumArgs); hash = hash_combine(hash, Selector.Identifiers.size()); for (auto piece : Selector.Identifiers) hash = hash_combine(hash, static_cast(piece)); @@ -313,7 +313,7 @@ template <> struct DenseMapInfo { static bool isEqual(const clang::api_notes::StoredObjCSelector &LHS, const clang::api_notes::StoredObjCSelector &RHS) { -return LHS.NumPieces == RHS.NumPieces && LHS.Identifiers == RHS.Identifiers; +return LHS.NumArgs == RHS.NumArgs && LHS.Identifiers == RHS.Identifiers; } }; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index 2cbf5fd3bf50301..01177b9b1d04dde 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -421,7 +421,7 @@ class ObjCSelectorTableInfo { static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { internal_key_type Key; -Key.NumPieces = +Key.NumArgs = endian::readNext(Data); unsigned NumIdents = (Length - sizeof(uint16_t)) / sizeof(uint32_t); for (unsigned i = 0; i != NumIdents; ++i) { diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 770d78e22050c01..62a2ab1799913a1 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -823,7 +823,7 @@ class ObjCSelectorTableInfo { void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { llvm::support::endian::Writer writer(OS, llvm::endianness::little); -writer.write(Key.NumPieces); +writer.write(Key.NumArgs); for (auto Identifier : Key.Identifiers) writer.write(Identifier); } >From a95d72d013f31511350fb263c27afbc41ff7744b Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:45:11 + Subject: [PATCH 2/2] [APINotes] Upstream APINotes YAML compiler This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/APINotes/APINotesYAMLCompiler.h | 11 + clang/include/clang/APINotes/Types.h | 1 + clang/lib/APINotes/APINotesReader.cpp | 1 + clang/lib/APINotes/APINotesYAMLCompiler.cpp | 474 +- 4 files changed, 486 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/APINotes/APINotesYAMLCompiler.h b/clang/include/clang/APINotes/APINotesYAMLCompiler.h index 6098d0ee36fc477..9c24ed85b6a124a 100644 --- a/clang/include/clang/APINotes/APINotesYAMLCompiler.h +++ b/clang/include/clang/APINotes/APINotesYAMLCompiler.h @@ -10,14 +10,25 @@ #define LLVM_CLANG_APINOTES_APINOTESYAMLCOMPILER_H #include "llvm/ADT/StringRef.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +namespace clang { +class FileEntry; +} // namespace clang + namespace clang { namespace api_notes { /// Parses the APINotes YAML content and writes the representation back to the /// specified stream. This provides a means of testing the YAML processing of /// the APINotes format. bool parseAndDumpAPINotes(llvm::StringRef YI, llvm::raw_ostream &OS); + +/// Converts API notes from YAML format to binary format. +bool compileAPINotes(llvm::StringRef YAMLInput, const FileEntry *SourceFile, + llvm::raw_ostream &OS, + llvm::SourceMgr::DiagHandlerTy DiagHandler = nullptr, + void *DiagHandlerCtxt = nullptr); } // namespace api_notes } // namespace clang diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index b74244bc8f1cbd3..79595abcf7d02d9 100644 --
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/71413 >From f80d68edf0787821531c0f88d845b253703ef13e Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:41:19 + Subject: [PATCH 1/2] [APINotes] NFC: rename `StoredObjCSelector::NumPieces` This value actually represents a number of arguments the selector takes, not the number of identifiers. These will be different if the selector takes no arguments. --- clang/lib/APINotes/APINotesFormat.h | 6 +++--- clang/lib/APINotes/APINotesReader.cpp | 2 +- clang/lib/APINotes/APINotesWriter.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 5897b45d3796d0e..615314c46f09cac 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -247,7 +247,7 @@ using EnumConstantDataLayout = /// A stored Objective-C selector. struct StoredObjCSelector { - unsigned NumPieces; + unsigned NumArgs; llvm::SmallVector Identifiers; }; @@ -302,7 +302,7 @@ template <> struct DenseMapInfo { static unsigned getHashValue(const clang::api_notes::StoredObjCSelector &Selector) { -auto hash = llvm::hash_value(Selector.NumPieces); +auto hash = llvm::hash_value(Selector.NumArgs); hash = hash_combine(hash, Selector.Identifiers.size()); for (auto piece : Selector.Identifiers) hash = hash_combine(hash, static_cast(piece)); @@ -313,7 +313,7 @@ template <> struct DenseMapInfo { static bool isEqual(const clang::api_notes::StoredObjCSelector &LHS, const clang::api_notes::StoredObjCSelector &RHS) { -return LHS.NumPieces == RHS.NumPieces && LHS.Identifiers == RHS.Identifiers; +return LHS.NumArgs == RHS.NumArgs && LHS.Identifiers == RHS.Identifiers; } }; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index 2cbf5fd3bf50301..01177b9b1d04dde 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -421,7 +421,7 @@ class ObjCSelectorTableInfo { static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { internal_key_type Key; -Key.NumPieces = +Key.NumArgs = endian::readNext(Data); unsigned NumIdents = (Length - sizeof(uint16_t)) / sizeof(uint32_t); for (unsigned i = 0; i != NumIdents; ++i) { diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 770d78e22050c01..62a2ab1799913a1 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -823,7 +823,7 @@ class ObjCSelectorTableInfo { void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { llvm::support::endian::Writer writer(OS, llvm::endianness::little); -writer.write(Key.NumPieces); +writer.write(Key.NumArgs); for (auto Identifier : Key.Identifiers) writer.write(Identifier); } >From 59c1842e8c3ba87138186f089faf7218f8568455 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:45:11 + Subject: [PATCH 2/2] [APINotes] Upstream APINotes YAML compiler This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/APINotes/APINotesYAMLCompiler.h | 11 + clang/include/clang/APINotes/Types.h | 1 + clang/lib/APINotes/APINotesReader.cpp | 1 + clang/lib/APINotes/APINotesYAMLCompiler.cpp | 480 +- 4 files changed, 492 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/APINotes/APINotesYAMLCompiler.h b/clang/include/clang/APINotes/APINotesYAMLCompiler.h index 6098d0ee36fc477..9c24ed85b6a124a 100644 --- a/clang/include/clang/APINotes/APINotesYAMLCompiler.h +++ b/clang/include/clang/APINotes/APINotesYAMLCompiler.h @@ -10,14 +10,25 @@ #define LLVM_CLANG_APINOTES_APINOTESYAMLCOMPILER_H #include "llvm/ADT/StringRef.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +namespace clang { +class FileEntry; +} // namespace clang + namespace clang { namespace api_notes { /// Parses the APINotes YAML content and writes the representation back to the /// specified stream. This provides a means of testing the YAML processing of /// the APINotes format. bool parseAndDumpAPINotes(llvm::StringRef YI, llvm::raw_ostream &OS); + +/// Converts API notes from YAML format to binary format. +bool compileAPINotes(llvm::StringRef YAMLInput, const FileEntry *SourceFile, + llvm::raw_ostream &OS, + llvm::SourceMgr::DiagHandlerTy DiagHandler = nullptr, + void *DiagHandlerCtxt = nullptr); } // namespace api_notes } // namespace clang diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index b74244bc8f1cbd3..79595abcf7d02d9 100644 --
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + +"is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef selectorRef; +selectorRef.NumArgs = !takesArguments ? 0 : a.size(); +selectorRef.Identifiers = a; + +// Translate the initializer info. +MInfo.DesignatedInit = TheMethod.DesignatedInit; +MInfo.RequiredInit = TheMethod.Required; +if (TheMethod.FactoryAsInit != FactoryAsInitKind::Infer) { + emitError("'Fact
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/71413 >From f80d68edf0787821531c0f88d845b253703ef13e Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:41:19 + Subject: [PATCH 1/2] [APINotes] NFC: rename `StoredObjCSelector::NumPieces` This value actually represents a number of arguments the selector takes, not the number of identifiers. These will be different if the selector takes no arguments. --- clang/lib/APINotes/APINotesFormat.h | 6 +++--- clang/lib/APINotes/APINotesReader.cpp | 2 +- clang/lib/APINotes/APINotesWriter.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 5897b45d3796d0e..615314c46f09cac 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -247,7 +247,7 @@ using EnumConstantDataLayout = /// A stored Objective-C selector. struct StoredObjCSelector { - unsigned NumPieces; + unsigned NumArgs; llvm::SmallVector Identifiers; }; @@ -302,7 +302,7 @@ template <> struct DenseMapInfo { static unsigned getHashValue(const clang::api_notes::StoredObjCSelector &Selector) { -auto hash = llvm::hash_value(Selector.NumPieces); +auto hash = llvm::hash_value(Selector.NumArgs); hash = hash_combine(hash, Selector.Identifiers.size()); for (auto piece : Selector.Identifiers) hash = hash_combine(hash, static_cast(piece)); @@ -313,7 +313,7 @@ template <> struct DenseMapInfo { static bool isEqual(const clang::api_notes::StoredObjCSelector &LHS, const clang::api_notes::StoredObjCSelector &RHS) { -return LHS.NumPieces == RHS.NumPieces && LHS.Identifiers == RHS.Identifiers; +return LHS.NumArgs == RHS.NumArgs && LHS.Identifiers == RHS.Identifiers; } }; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index 2cbf5fd3bf50301..01177b9b1d04dde 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -421,7 +421,7 @@ class ObjCSelectorTableInfo { static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { internal_key_type Key; -Key.NumPieces = +Key.NumArgs = endian::readNext(Data); unsigned NumIdents = (Length - sizeof(uint16_t)) / sizeof(uint32_t); for (unsigned i = 0; i != NumIdents; ++i) { diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 770d78e22050c01..62a2ab1799913a1 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -823,7 +823,7 @@ class ObjCSelectorTableInfo { void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { llvm::support::endian::Writer writer(OS, llvm::endianness::little); -writer.write(Key.NumPieces); +writer.write(Key.NumArgs); for (auto Identifier : Key.Identifiers) writer.write(Identifier); } >From 251611692dba90fc95df29c981821dd954de1e1d Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 6 Nov 2023 15:45:11 + Subject: [PATCH 2/2] [APINotes] Upstream APINotes YAML compiler This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../clang/APINotes/APINotesYAMLCompiler.h | 11 + clang/include/clang/APINotes/Types.h | 1 + clang/lib/APINotes/APINotesReader.cpp | 1 + clang/lib/APINotes/APINotesYAMLCompiler.cpp | 478 +- 4 files changed, 490 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/APINotes/APINotesYAMLCompiler.h b/clang/include/clang/APINotes/APINotesYAMLCompiler.h index 6098d0ee36fc477..9c24ed85b6a124a 100644 --- a/clang/include/clang/APINotes/APINotesYAMLCompiler.h +++ b/clang/include/clang/APINotes/APINotesYAMLCompiler.h @@ -10,14 +10,25 @@ #define LLVM_CLANG_APINOTES_APINOTESYAMLCOMPILER_H #include "llvm/ADT/StringRef.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +namespace clang { +class FileEntry; +} // namespace clang + namespace clang { namespace api_notes { /// Parses the APINotes YAML content and writes the representation back to the /// specified stream. This provides a means of testing the YAML processing of /// the APINotes format. bool parseAndDumpAPINotes(llvm::StringRef YI, llvm::raw_ostream &OS); + +/// Converts API notes from YAML format to binary format. +bool compileAPINotes(llvm::StringRef YAMLInput, const FileEntry *SourceFile, + llvm::raw_ostream &OS, + llvm::SourceMgr::DiagHandlerTy DiagHandler = nullptr, + void *DiagHandlerCtxt = nullptr); } // namespace api_notes } // namespace clang diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index b74244bc8f1cbd3..79595abcf7d02d9 100644 --
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &TheModule; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + bool convertAvailability(const AvailabilityItem &In, + CommonEntityInfo &OutInfo, llvm::StringRef APIName) { +// Populate the unavailability information. +OutInfo.Unavailable = (In.Mode == APIAvailability::None); +OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift); +if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) { + OutInfo.UnavailableMsg = std::string(In.Msg); +} else { + if (!In.Msg.empty()) { +emitError("availability message for available API '" + APIName + + "' will not be used"); + } +} +return false; + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + while (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.push_back(ParamInfo()); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional NullabilityOfRet, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError("nullability info for " + APIName + " does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (auto i = Nullability.begin(), e = Nullability.end(); i != e; + ++i, ++idx) { + OutInfo.addTypeInfo(idx, *i); + audited = true; +} +if (NullabilityOfRet) { + OutInfo.addTypeInfo(0, *NullabilityOfRet); + audited = true; +} else if (audited) { + OutInfo.addTypeInfo(0, NullabilityKind::NonNull); +} +if (audited) { + OutInfo.NullabilityAudited = audited; + OutInfo.NumAdjustedNullable = idx; +} + } + + /// Convert the common parts of an entity from YAML. + template + bool convertCommon(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); +return false; + } + + /// Convert the common parts of a type entity from YAML. + template + bool convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +if (convertCommon(Common, Info, APIName)) + return true; + +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); +return false; + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &TheMethod, ContextID ClassID, + StringRef ClassName, VersionTuple SwiftVersion) { +ObjCMethodInfo MInfo; + +if (convertCommon(TheMethod, MInfo, TheMethod.Selector)) + return; + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = TheMethod.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector a; +TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && a.size() > 1) { + emitError("selector " + TheMethod.Selector + +"is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef selectorRef; +selectorRef.NumArgs = !takesArguments ? 0 : a.size(); +selectorRef.Identifiers = a; + +// Translate the initializer info. +MInfo.DesignatedInit = TheMethod.DesignatedInit; +MInfo.RequiredInit = TheMethod.Required; +if (TheMethod.FactoryAsInit != FactoryAsInitKind::Infer) { + emitError("'Fact
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,478 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &M; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : M(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + void convertAvailability(const AvailabilityItem &Availability, + CommonEntityInfo &CEI, llvm::StringRef APIName) { +// Populate the unavailability information. +CEI.Unavailable = (Availability.Mode == APIAvailability::None); +CEI.UnavailableInSwift = (Availability.Mode == APIAvailability::NonSwift); +if (CEI.Unavailable || CEI.UnavailableInSwift) { + CEI.UnavailableMsg = std::string(Availability.Msg); +} else { + if (!Availability.Msg.empty()) { +emitError(llvm::Twine("availability message for available API '") + + APIName + "' will not be used"); + } +} + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + if (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.resize(P.Position + 1); + } egorzhdan wrote: Fixed https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,478 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &M; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : M(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + void convertAvailability(const AvailabilityItem &Availability, + CommonEntityInfo &CEI, llvm::StringRef APIName) { +// Populate the unavailability information. +CEI.Unavailable = (Availability.Mode == APIAvailability::None); +CEI.UnavailableInSwift = (Availability.Mode == APIAvailability::NonSwift); +if (CEI.Unavailable || CEI.UnavailableInSwift) { + CEI.UnavailableMsg = std::string(Availability.Msg); +} else { + if (!Availability.Msg.empty()) { +emitError(llvm::Twine("availability message for available API '") + + APIName + "' will not be used"); + } +} + } + + void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) { +for (const auto &P : Params) { + ParamInfo PI; + if (P.Nullability) +PI.setNullabilityAudited(*P.Nullability); + PI.setNoEscape(P.NoEscape); + PI.setType(std::string(P.Type)); + PI.setRetainCountConvention(P.RetainCountConvention); + if (OutInfo.Params.size() <= P.Position) { +OutInfo.Params.resize(P.Position + 1); + } + OutInfo.Params[P.Position] |= PI; +} + } + + void convertNullability(const NullabilitySeq &Nullability, + std::optional ReturnNullability, + FunctionInfo &OutInfo, llvm::StringRef APIName) { +if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) { + emitError(llvm::Twine("nullability info for '") + APIName + +"' does not fit"); + return; +} + +bool audited = false; +unsigned int idx = 1; +for (const auto &N : Nullability) + OutInfo.addTypeInfo(idx++, N); +audited = Nullability.size() > 0 || ReturnNullability; +if (audited) + OutInfo.addTypeInfo(0, ReturnNullability ? *ReturnNullability + : NullabilityKind::NonNull); +if (!audited) + return; +OutInfo.NullabilityAudited = audited; +OutInfo.NumAdjustedNullable = idx; + } + + /// Convert the common parts of an entity from YAML. + template + void convertCommonEntity(const T &Common, CommonEntityInfo &Info, + StringRef APIName) { +convertAvailability(Common.Availability, Info, APIName); +Info.setSwiftPrivate(Common.SwiftPrivate); +Info.SwiftName = std::string(Common.SwiftName); + } + + /// Convert the common parts of a type entity from YAML. + template + void convertCommonType(const T &Common, CommonTypeInfo &Info, + StringRef APIName) { +convertCommonEntity(Common, Info, APIName); +if (Common.SwiftBridge) + Info.setSwiftBridge(std::string(*Common.SwiftBridge)); +Info.setNSErrorDomain(Common.NSErrorDomain); + } + + // Translate from Method into ObjCMethodInfo and write it out. + void convertMethod(const Method &M, ContextID ClassID, StringRef ClassName, + VersionTuple SwiftVersion) { +ObjCMethodInfo MI; +convertCommonEntity(M, MI, M.Selector); + +// Check if the selector ends with ':' to determine if it takes arguments. +bool takesArguments = M.Selector.endswith(":"); + +// Split the selector into pieces. +llvm::SmallVector Args; +M.Selector.split(Args, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); +if (!takesArguments && Args.size() > 1) { + emitError("selector '" + M.Selector + "' is missing a ':' at the end"); + return; +} + +// Construct ObjCSelectorRef. +api_notes::ObjCSelectorRef Selector; +Selector.NumArgs = !takesArguments ? 0 : Args.size(); +Selector.Identifiers = Args; + +// Translate the initializer info. +MI.DesignatedInit = M.DesignatedInit; +MI.RequiredInit = M.Required; +if (M.FactoryAsInit != FactoryAsInitKind::Infer) + emitError("'FactoryAsInit' is no longer valid; use 'SwiftName' instead"); + +MI.ResultType = std::string(M.ResultType); + +// Translate parameter information. +convertParams(M.P
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
@@ -635,3 +638,478 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, return false; } + +namespace { +using namespace api_notes; + +class YAMLConverter { + const Module &M; + APINotesWriter Writer; + llvm::raw_ostream &OS; + llvm::SourceMgr::DiagHandlerTy DiagHandler; + void *DiagHandlerCtxt; + bool ErrorOccured; + + /// Emit a diagnostic + bool emitError(llvm::Twine Message) { +DiagHandler( +llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()), +DiagHandlerCtxt); +ErrorOccured = true; +return true; + } + +public: + YAMLConverter(const Module &TheModule, const FileEntry *SourceFile, +llvm::raw_ostream &OS, +llvm::SourceMgr::DiagHandlerTy DiagHandler, +void *DiagHandlerCtxt) + : M(TheModule), Writer(TheModule.Name, SourceFile), OS(OS), +DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt), +ErrorOccured(false) {} + + void convertAvailability(const AvailabilityItem &Availability, + CommonEntityInfo &CEI, llvm::StringRef APIName) { +// Populate the unavailability information. +CEI.Unavailable = (Availability.Mode == APIAvailability::None); +CEI.UnavailableInSwift = (Availability.Mode == APIAvailability::NonSwift); +if (CEI.Unavailable || CEI.UnavailableInSwift) { + CEI.UnavailableMsg = std::string(Availability.Msg); +} else { + if (!Availability.Msg.empty()) { +emitError(llvm::Twine("availability message for available API '") + + APIName + "' will not be used"); + } egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/71413 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/72389 This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes >From 2550d96acc9ce134b4f7359af0c75e3bd3146484 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 15 Nov 2023 13:46:54 + Subject: [PATCH] [APINotes] Upstream APINotesManager This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../include/clang/APINotes/APINotesManager.h | 163 ++ clang/include/clang/APINotes/Types.h | 3 + .../clang/Basic/DiagnosticCommonKinds.td | 13 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Basic/Module.h| 3 + clang/include/clang/Basic/SourceMgrAdapter.h | 85 clang/lib/APINotes/APINotesManager.cpp| 469 ++ clang/lib/APINotes/CMakeLists.txt | 1 + clang/lib/Basic/CMakeLists.txt| 1 + clang/lib/Basic/SourceMgrAdapter.cpp | 136 + 10 files changed, 876 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesManager.h create mode 100644 clang/include/clang/Basic/SourceMgrAdapter.h create mode 100644 clang/lib/APINotes/APINotesManager.cpp create mode 100644 clang/lib/Basic/SourceMgrAdapter.cpp diff --git a/clang/include/clang/APINotes/APINotesManager.h b/clang/include/clang/APINotes/APINotesManager.h new file mode 100644 index 000..d82d1fa2d544a1d --- /dev/null +++ b/clang/include/clang/APINotes/APINotesManager.h @@ -0,0 +1,163 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesFile); + + /// Look f
[clang] [APINotes] Upstream APINotesManager (PR #72389)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/72389 >From fef3782ff1d4f2344b98eae4cf339e8cc1239fd7 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 15 Nov 2023 13:46:54 + Subject: [PATCH] [APINotes] Upstream APINotesManager This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../include/clang/APINotes/APINotesManager.h | 163 ++ clang/include/clang/APINotes/Types.h | 3 + .../clang/Basic/DiagnosticCommonKinds.td | 13 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Basic/Module.h| 3 + clang/include/clang/Basic/SourceMgrAdapter.h | 85 clang/lib/APINotes/APINotesManager.cpp| 469 ++ clang/lib/APINotes/CMakeLists.txt | 1 + clang/lib/Basic/CMakeLists.txt| 1 + clang/lib/Basic/SourceMgrAdapter.cpp | 136 + 10 files changed, 876 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesManager.h create mode 100644 clang/include/clang/Basic/SourceMgrAdapter.h create mode 100644 clang/lib/APINotes/APINotesManager.cpp create mode 100644 clang/lib/Basic/SourceMgrAdapter.cpp diff --git a/clang/include/clang/APINotes/APINotesManager.h b/clang/include/clang/APINotes/APINotesManager.h new file mode 100644 index 000..d82d1fa2d544a1d --- /dev/null +++ b/clang/include/clang/APINotes/APINotesManager.h @@ -0,0 +1,163 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesFile); + + /// Look for API notes in the given directory. + /// + /// This might find either a binary or source API notes. + OptionalFileEntryRef findAPINotesFile(DirectoryEntryRef Directory, +
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) egorzhdan wrote: Not quite, `Readers` is a `DenseMap` where the value type is a `PointerUnion`, so we need to cast it to one of the possible types which is `APINotesReader *`. I like the idea of making `CurrentModuleReaders` an array of unique pointers regardless. I'll go ahead and do that. https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/72389 >From aa80c53b94e0d0a4ae86be41b47f8837a96b39d9 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 15 Nov 2023 13:46:54 + Subject: [PATCH] [APINotes] Upstream APINotesManager This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../include/clang/APINotes/APINotesManager.h | 169 +++ clang/include/clang/APINotes/Types.h | 3 + .../clang/Basic/DiagnosticCommonKinds.td | 13 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Basic/Module.h| 3 + clang/include/clang/Basic/SourceMgrAdapter.h | 85 clang/lib/APINotes/APINotesManager.cpp| 458 ++ clang/lib/APINotes/CMakeLists.txt | 1 + clang/lib/Basic/CMakeLists.txt| 1 + clang/lib/Basic/SourceMgrAdapter.cpp | 136 ++ 10 files changed, 871 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesManager.h create mode 100644 clang/include/clang/Basic/SourceMgrAdapter.h create mode 100644 clang/lib/APINotes/APINotesManager.cpp create mode 100644 clang/lib/Basic/SourceMgrAdapter.cpp diff --git a/clang/include/clang/APINotes/APINotesManager.h b/clang/include/clang/APINotes/APINotesManager.h new file mode 100644 index 000..f1b346e181aae9c --- /dev/null +++ b/clang/include/clang/APINotes/APINotesManager.h @@ -0,0 +1,169 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + enum ReaderKind : unsigned { Public = 0, Private = 1 }; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesFile); + + /// Look for API notes in the given directory. + /// + /// This might find either a binary or source API notes. + Option
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,163 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; egorzhdan wrote: That makes sense, I added an enum. https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,163 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesFile); + + /// Look for API notes in the given directory. + /// + /// This might find either a binary or source API notes. + OptionalFileEntryRef findAPINotesFile(DirectoryEntryRef Directory, +StringRef FileName, +bool WantPublic = true); + + /// Attempt to load API notes for the given framework. + /// + /// \param FrameworkPath The path to the framework. + /// \param Public Whether to load the public API notes. Otherwise, attempt + /// to load the private API notes. + /// + /// \returns the header directory entry (e.g., for Headers or PrivateHeaders) + /// for which the API notes were successfully loaded, or NULL if API notes + /// could not be loaded for any reason. + OptionalDirectoryEntryRef loadFrameworkAPINotes(llvm::StringRef FrameworkPath, egorzhdan wrote: A framework will have the API notes file under either `{framework root}/APINotes`, `{framework root}/Headers` or `{framework root}/PrivateHeaders`, while a library will have API notes simply in its directory. https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,163 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesFile); + + /// Look for API notes in the given directory. + /// + /// This might find either a binary or source API notes. + OptionalFileEntryRef findAPINotesFile(DirectoryEntryRef Directory, +StringRef FileName, +bool WantPublic = true); + + /// Attempt to load API notes for the given framework. + /// + /// \param FrameworkPath The path to the framework. + /// \param Public Whether to load the public API notes. Otherwise, attempt + /// to load the private API notes. + /// + /// \returns the header directory entry (e.g., for Headers or PrivateHeaders) + /// for which the API notes were successfully loaded, or NULL if API notes + /// could not be loaded for any reason. + OptionalDirectoryEntryRef loadFrameworkAPINotes(llvm::StringRef FrameworkPath, + llvm::StringRef FrameworkName, + bool Public); + +public: + APINotesManager(SourceManager &SM, const LangOptions &LangOpts); + ~APINotesManager(); + + /// Set the Swift version to use when filtering API notes. + void setSwiftVersion(llvm::VersionTuple Version) { +this->SwiftVersion = Version; + } + + /// Load the API notes for the current module. + /// + /// \param M The current module. + /// \param LookInModule Whether to look inside the module itself. egorzhdan wrote: Clarified the comment to indicate that we really mean looking into the directory of the current module. https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llv
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,163 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesFile); + + /// Look for API notes in the given directory. + /// + /// This might find either a binary or source API notes. + OptionalFileEntryRef findAPINotesFile(DirectoryEntryRef Directory, +StringRef FileName, +bool WantPublic = true); + + /// Attempt to load API notes for the given framework. + /// + /// \param FrameworkPath The path to the framework. + /// \param Public Whether to load the public API notes. Otherwise, attempt + /// to load the private API notes. + /// + /// \returns the header directory entry (e.g., for Headers or PrivateHeaders) + /// for which the API notes were successfully loaded, or NULL if API notes + /// could not be loaded for any reason. + OptionalDirectoryEntryRef loadFrameworkAPINotes(llvm::StringRef FrameworkPath, + llvm::StringRef FrameworkName, + bool Public); + +public: + APINotesManager(SourceManager &SM, const LangOptions &LangOpts); + ~APINotesManager(); + + /// Set the Swift version to use when filtering API notes. + void setSwiftVersion(llvm::VersionTuple Version) { +this->SwiftVersion = Version; + } + + /// Load the API notes for the current module. + /// + /// \param M The current module. + /// \param LookInModule Whether to look inside the module itself. + /// \param SearchPaths The paths in which we should search for API notes + /// for the current module. + /// + /// \returns true if API notes were successfully loaded, \c false otherwise. + bool loadCurrentModuleAPINotes(Module *M, bool LookInModule, + ArrayRef Searc
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -737,6 +737,9 @@ inline bool operator!=(const TypedefInfo &LHS, const TypedefInfo &RHS) { return !(LHS == RHS); } +/// The file extension used for the source representation of API notes. +static const char SOURCE_APINOTES_EXTENSION[] = "apinotes"; egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) + delete Reader; + } + + delete CurrentModuleReaders[0]; + delete CurrentModuleReaders[1]; +} + +std::unique_ptr +APINotesManager::loadAPINotes(FileEntryRef APINotesFile) { + PrettyStackTraceDoubleString Trace("Loading API notes from ", + APINotesFile.getName()); + + // Open the source file. + auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User); + auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation()); + if (!SourceBuffer) +return nullptr; + + // Compile the API notes source into a buffer. + // FIXME: Either propagate OSType through or, better yet, improve the binary + // APINotes format to maintain complete availability information. + // FIXME: We don't even really need to go through the binary format at all; + // we're just going to immediately deserialize it again. + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + { +SourceMgrAdapter SMAdapter( +SM, SM.getDiagnostics(), diag::err_apinotes_message, +diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile); +llvm::raw_svector_ostream OS(APINotesBuffer); +if (api_notes::compileAPINotes( +SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS, +SMAdapter.getDiagHandler(), SMAdapter.getDiagContext())) + return nullptr; + +// Make a copy of the compiled form into the buffer. +CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( +StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + } + + // Load the binary form we just compiled. + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +} + +std::unique_ptr +APINotesManager::loadAPINotes(StringRef Buffer) { + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + SourceMgrAdapter SMAdapter( + SM, SM.getDiagnostics(), diag::err_apinotes_message, + diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt); + llvm::raw_svector_ostream OS(APINotesBuffer); + + if (api_notes::compileAPINotes(Buffer, nullptr, OS, + SMAdapter.getDiagHandler(), + SMAdapter.getDiagContext())) +return nullptr; + + CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( + StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) + delete Reader; + } + + delete CurrentModuleReaders[0]; + delete CurrentModuleReaders[1]; +} + +std::unique_ptr +APINotesManager::loadAPINotes(FileEntryRef APINotesFile) { + PrettyStackTraceDoubleString Trace("Loading API notes from ", + APINotesFile.getName()); + + // Open the source file. + auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User); + auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation()); + if (!SourceBuffer) +return nullptr; + + // Compile the API notes source into a buffer. + // FIXME: Either propagate OSType through or, better yet, improve the binary + // APINotes format to maintain complete availability information. + // FIXME: We don't even really need to go through the binary format at all; + // we're just going to immediately deserialize it again. + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + { +SourceMgrAdapter SMAdapter( +SM, SM.getDiagnostics(), diag::err_apinotes_message, +diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile); +llvm::raw_svector_ostream OS(APINotesBuffer); +if (api_notes::compileAPINotes( +SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS, +SMAdapter.getDiagHandler(), SMAdapter.getDiagContext())) + return nullptr; + +// Make a copy of the compiled form into the buffer. +CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( +StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + } + + // Load the binary form we just compiled. + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +} + +std::unique_ptr +APINotesManager::loadAPINotes(StringRef Buffer) { + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + SourceMgrAdapter SMAdapter( + SM, SM.getDiagnostics(), diag::err_apinotes_message, + diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt); + llvm::raw_svector_ostream OS(APINotesBuffer); + + if (api_notes::compileAPINotes(Buffer, nullptr, OS, + SMAdapter.getDiagHandler(), + SMAdapter.getDiagContext())) +return nullptr; + + CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( + StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) + delete Reader; + } + + delete CurrentModuleReaders[0]; + delete CurrentModuleReaders[1]; +} + +std::unique_ptr +APINotesManager::loadAPINotes(FileEntryRef APINotesFile) { + PrettyStackTraceDoubleString Trace("Loading API notes from ", + APINotesFile.getName()); + + // Open the source file. + auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User); + auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation()); + if (!SourceBuffer) +return nullptr; + + // Compile the API notes source into a buffer. + // FIXME: Either propagate OSType through or, better yet, improve the binary + // APINotes format to maintain complete availability information. + // FIXME: We don't even really need to go through the binary format at all; + // we're just going to immediately deserialize it again. + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + { +SourceMgrAdapter SMAdapter( +SM, SM.getDiagnostics(), diag::err_apinotes_message, +diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile); +llvm::raw_svector_ostream OS(APINotesBuffer); +if (api_notes::compileAPINotes( +SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS, +SMAdapter.getDiagHandler(), SMAdapter.getDiagContext())) + return nullptr; + +// Make a copy of the compiled form into the buffer. +CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( +StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + } + + // Load the binary form we just compiled. + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +} + +std::unique_ptr +APINotesManager::loadAPINotes(StringRef Buffer) { + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + SourceMgrAdapter SMAdapter( + SM, SM.getDiagnostics(), diag::err_apinotes_message, + diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt); + llvm::raw_svector_ostream OS(APINotesBuffer); + + if (api_notes::compileAPINotes(Buffer, nullptr, OS, + SMAdapter.getDiagHandler(), + SMAdapter.getDiagContext())) +return nullptr; + + CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( + StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) + delete Reader; + } + + delete CurrentModuleReaders[0]; + delete CurrentModuleReaders[1]; +} + +std::unique_ptr +APINotesManager::loadAPINotes(FileEntryRef APINotesFile) { + PrettyStackTraceDoubleString Trace("Loading API notes from ", + APINotesFile.getName()); + + // Open the source file. + auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User); + auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation()); + if (!SourceBuffer) +return nullptr; + + // Compile the API notes source into a buffer. + // FIXME: Either propagate OSType through or, better yet, improve the binary + // APINotes format to maintain complete availability information. + // FIXME: We don't even really need to go through the binary format at all; + // we're just going to immediately deserialize it again. + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + { +SourceMgrAdapter SMAdapter( +SM, SM.getDiagnostics(), diag::err_apinotes_message, +diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile); +llvm::raw_svector_ostream OS(APINotesBuffer); +if (api_notes::compileAPINotes( +SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS, +SMAdapter.getDiagHandler(), SMAdapter.getDiagContext())) + return nullptr; + +// Make a copy of the compiled form into the buffer. +CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( +StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + } + + // Load the binary form we just compiled. + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +} + +std::unique_ptr +APINotesManager::loadAPINotes(StringRef Buffer) { + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + SourceMgrAdapter SMAdapter( + SM, SM.getDiagnostics(), diag::err_apinotes_message, + diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt); + llvm::raw_svector_ostream OS(APINotesBuffer); + + if (api_notes::compileAPINotes(Buffer, nullptr, OS, + SMAdapter.getDiagHandler(), + SMAdapter.getDiagContext())) +return nullptr; + + CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( + StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) + delete Reader; + } + + delete CurrentModuleReaders[0]; + delete CurrentModuleReaders[1]; +} + +std::unique_ptr +APINotesManager::loadAPINotes(FileEntryRef APINotesFile) { + PrettyStackTraceDoubleString Trace("Loading API notes from ", + APINotesFile.getName()); + + // Open the source file. + auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User); + auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation()); + if (!SourceBuffer) +return nullptr; + + // Compile the API notes source into a buffer. + // FIXME: Either propagate OSType through or, better yet, improve the binary + // APINotes format to maintain complete availability information. + // FIXME: We don't even really need to go through the binary format at all; + // we're just going to immediately deserialize it again. + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + { +SourceMgrAdapter SMAdapter( +SM, SM.getDiagnostics(), diag::err_apinotes_message, +diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile); +llvm::raw_svector_ostream OS(APINotesBuffer); +if (api_notes::compileAPINotes( +SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS, +SMAdapter.getDiagHandler(), SMAdapter.getDiagContext())) + return nullptr; + +// Make a copy of the compiled form into the buffer. +CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( +StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + } + + // Load the binary form we just compiled. + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +} + +std::unique_ptr +APINotesManager::loadAPINotes(StringRef Buffer) { + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + SourceMgrAdapter SMAdapter( + SM, SM.getDiagnostics(), diag::err_apinotes_message, + diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt); + llvm::raw_svector_ostream OS(APINotesBuffer); + + if (api_notes::compileAPINotes(Buffer, nullptr, OS, + SMAdapter.getDiagHandler(), + SMAdapter.getDiagContext())) +return nullptr; + + CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( + StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) + delete Reader; + } + + delete CurrentModuleReaders[0]; + delete CurrentModuleReaders[1]; +} + +std::unique_ptr +APINotesManager::loadAPINotes(FileEntryRef APINotesFile) { + PrettyStackTraceDoubleString Trace("Loading API notes from ", + APINotesFile.getName()); + + // Open the source file. + auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User); + auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation()); + if (!SourceBuffer) +return nullptr; + + // Compile the API notes source into a buffer. + // FIXME: Either propagate OSType through or, better yet, improve the binary + // APINotes format to maintain complete availability information. + // FIXME: We don't even really need to go through the binary format at all; + // we're just going to immediately deserialize it again. + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + { +SourceMgrAdapter SMAdapter( +SM, SM.getDiagnostics(), diag::err_apinotes_message, +diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile); +llvm::raw_svector_ostream OS(APINotesBuffer); +if (api_notes::compileAPINotes( +SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS, +SMAdapter.getDiagHandler(), SMAdapter.getDiagContext())) + return nullptr; + +// Make a copy of the compiled form into the buffer. +CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( +StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + } + + // Load the binary form we just compiled. + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +} + +std::unique_ptr +APINotesManager::loadAPINotes(StringRef Buffer) { + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + SourceMgrAdapter SMAdapter( + SM, SM.getDiagnostics(), diag::err_apinotes_message, + diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt); + llvm::raw_svector_ostream OS(APINotesBuffer); + + if (api_notes::compileAPINotes(Buffer, nullptr, OS, + SMAdapter.getDiagHandler(), + SMAdapter.getDiagContext())) +return nullptr; + + CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( + StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) egorzhdan wrote: Just realized that using `unique_ptr`s here is a bit tricky, because we are storing these pointers in `llvm::PointerUnion`. Looks like we'd increase the memory footprint by abandoning `llvm::PointerUnion`. Do you think it's still worth refactoring this? https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/72389 >From 9e171fa5e51a1c6572938da815f9d129f49fb046 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 15 Nov 2023 13:46:54 + Subject: [PATCH] [APINotes] Upstream APINotesManager This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../include/clang/APINotes/APINotesManager.h | 169 +++ clang/include/clang/APINotes/Types.h | 3 + .../clang/Basic/DiagnosticCommonKinds.td | 13 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Basic/Module.h| 3 + clang/include/clang/Basic/SourceMgrAdapter.h | 85 clang/lib/APINotes/APINotesManager.cpp| 458 ++ clang/lib/APINotes/CMakeLists.txt | 1 + clang/lib/Basic/CMakeLists.txt| 1 + clang/lib/Basic/SourceMgrAdapter.cpp | 136 ++ 10 files changed, 871 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesManager.h create mode 100644 clang/include/clang/Basic/SourceMgrAdapter.h create mode 100644 clang/lib/APINotes/APINotesManager.cpp create mode 100644 clang/lib/Basic/SourceMgrAdapter.cpp diff --git a/clang/include/clang/APINotes/APINotesManager.h b/clang/include/clang/APINotes/APINotesManager.h new file mode 100644 index 000..f1b346e181aae9c --- /dev/null +++ b/clang/include/clang/APINotes/APINotesManager.h @@ -0,0 +1,169 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + enum ReaderKind : unsigned { Public = 0, Private = 1 }; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesFile); + + /// Look for API notes in the given directory. + /// + /// This might find either a binary or source API notes. + Option
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) + delete Reader; + } + + delete CurrentModuleReaders[0]; + delete CurrentModuleReaders[1]; +} + +std::unique_ptr +APINotesManager::loadAPINotes(FileEntryRef APINotesFile) { + PrettyStackTraceDoubleString Trace("Loading API notes from ", + APINotesFile.getName()); + + // Open the source file. + auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User); + auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation()); + if (!SourceBuffer) +return nullptr; + + // Compile the API notes source into a buffer. + // FIXME: Either propagate OSType through or, better yet, improve the binary + // APINotes format to maintain complete availability information. + // FIXME: We don't even really need to go through the binary format at all; + // we're just going to immediately deserialize it again. + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + { +SourceMgrAdapter SMAdapter( +SM, SM.getDiagnostics(), diag::err_apinotes_message, +diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile); +llvm::raw_svector_ostream OS(APINotesBuffer); +if (api_notes::compileAPINotes( +SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS, +SMAdapter.getDiagHandler(), SMAdapter.getDiagContext())) + return nullptr; + +// Make a copy of the compiled form into the buffer. +CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( +StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + } + + // Load the binary form we just compiled. + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +} + +std::unique_ptr +APINotesManager::loadAPINotes(StringRef Buffer) { + llvm::SmallVector APINotesBuffer; + std::unique_ptr CompiledBuffer; + SourceMgrAdapter SMAdapter( + SM, SM.getDiagnostics(), diag::err_apinotes_message, + diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt); + llvm::raw_svector_ostream OS(APINotesBuffer); + + if (api_notes::compileAPINotes(Buffer, nullptr, OS, + SMAdapter.getDiagHandler(), + SMAdapter.getDiagContext())) +return nullptr; + + CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy( + StringRef(APINotesBuffer.data(), APINotesBuffer.size())); + auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion); + assert(Reader && "Could not load the API notes we just generated?"); + return Reader; +
[clang] [APINotes] Upstream APINotesManager (PR #72389)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/72389 >From c4c9e3bffdcc80d7c153c0c4945844876894d98e Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 15 Nov 2023 13:46:54 + Subject: [PATCH] [APINotes] Upstream APINotesManager This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- .../include/clang/APINotes/APINotesManager.h | 175 +++ clang/include/clang/APINotes/Types.h | 3 + .../clang/Basic/DiagnosticCommonKinds.td | 13 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Basic/Module.h| 3 + clang/include/clang/Basic/SourceMgrAdapter.h | 85 clang/lib/APINotes/APINotesManager.cpp| 458 ++ clang/lib/APINotes/CMakeLists.txt | 1 + clang/lib/Basic/CMakeLists.txt| 1 + clang/lib/Basic/SourceMgrAdapter.cpp | 136 ++ 10 files changed, 877 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesManager.h create mode 100644 clang/include/clang/Basic/SourceMgrAdapter.h create mode 100644 clang/lib/APINotes/APINotesManager.cpp create mode 100644 clang/lib/Basic/SourceMgrAdapter.cpp diff --git a/clang/include/clang/APINotes/APINotesManager.h b/clang/include/clang/APINotes/APINotesManager.h new file mode 100644 index 000..823b52ed28b5981 --- /dev/null +++ b/clang/include/clang/APINotes/APINotesManager.h @@ -0,0 +1,175 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + enum ReaderKind : unsigned { Public = 0, Private = 1 }; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + /// + /// Not using std::unique_ptr to store these, since the reader pointers are + /// also stored in llvm::PointerUnion below. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesF
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,163 @@ +//===--- APINotesManager.h - Manage API Notes Files -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H +#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class SourceManager; + +namespace api_notes { + +class APINotesReader; + +/// The API notes manager helps find API notes associated with declarations. +/// +/// API notes are externally-provided annotations for declarations that can +/// introduce new attributes (covering availability, nullability of +/// parameters/results, and so on) for specific declarations without directly +/// modifying the headers that contain those declarations. +/// +/// The API notes manager is responsible for finding and loading the +/// external API notes files that correspond to a given header. Its primary +/// operation is \c findAPINotes(), which finds the API notes reader that +/// provides information about the declarations at that location. +class APINotesManager { + using ReaderEntry = llvm::PointerUnion; + + SourceManager &SM; + + /// Whether to implicitly search for API notes files based on the + /// source file from which an entity was declared. + bool ImplicitAPINotes; + + /// The Swift version to use when interpreting versioned API notes. + llvm::VersionTuple SwiftVersion; + + /// API notes readers for the current module. + /// + /// There can be up to two of these, one for public headers and one + /// for private headers. + APINotesReader *CurrentModuleReaders[2] = {nullptr, nullptr}; + + /// A mapping from header file directories to the API notes reader for + /// that directory, or a redirection to another directory entry that may + /// have more information, or NULL to indicate that there is no API notes + /// reader for this directory. + llvm::DenseMap Readers; + + /// Load the API notes associated with the given file, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(FileEntryRef APINotesFile); + + /// Load the API notes associated with the given buffer, whether it is + /// the binary or source form of API notes. + /// + /// \returns the API notes reader for this file, or null if there is + /// a failure. + std::unique_ptr loadAPINotes(StringRef Buffer); + + /// Load the given API notes file for the given header directory. + /// + /// \param HeaderDir The directory at which we + /// + /// \returns true if an error occurred. + bool loadAPINotes(const DirectoryEntry *HeaderDir, FileEntryRef APINotesFile); + + /// Look for API notes in the given directory. + /// + /// This might find either a binary or source API notes. + OptionalFileEntryRef findAPINotesFile(DirectoryEntryRef Directory, +StringRef FileName, +bool WantPublic = true); + + /// Attempt to load API notes for the given framework. + /// + /// \param FrameworkPath The path to the framework. + /// \param Public Whether to load the public API notes. Otherwise, attempt + /// to load the private API notes. + /// + /// \returns the header directory entry (e.g., for Headers or PrivateHeaders) + /// for which the API notes were successfully loaded, or NULL if API notes + /// could not be loaded for any reason. + OptionalDirectoryEntryRef loadFrameworkAPINotes(llvm::StringRef FrameworkPath, egorzhdan wrote: Good point, added a comment to reflect that https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
@@ -0,0 +1,469 @@ +//===--- APINotesManager.cpp - Manage API Notes Files -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/APINotes/APINotesManager.h" +#include "clang/APINotes/APINotesReader.h" +#include "clang/APINotes/APINotesYAMLCompiler.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceMgrAdapter.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" + +using namespace clang; +using namespace api_notes; + +#define DEBUG_TYPE "API Notes" +STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded"); +STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded"); +STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded"); +STATISTIC(NumFrameworksSearched, "frameworks searched"); +STATISTIC(NumDirectoriesSearched, "header directories searched"); +STATISTIC(NumDirectoryCacheHits, "directory cache hits"); + +namespace { +/// Prints two successive strings, which much be kept alive as long as the +/// PrettyStackTrace entry. +class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry { + StringRef First, Second; + +public: + PrettyStackTraceDoubleString(StringRef First, StringRef Second) + : First(First), Second(Second) {} + void print(raw_ostream &OS) const override { OS << First << Second; } +}; +} // namespace + +APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts) +: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {} + +APINotesManager::~APINotesManager() { + // Free the API notes readers. + for (const auto &Entry : Readers) { +if (auto Reader = Entry.second.dyn_cast()) egorzhdan wrote: Done, added a comment https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesManager (PR #72389)
egorzhdan wrote: @nico sorry for not leaving a more detailed description. I'll make sure to add a release note once the API notes are upstreamed entirely. https://github.com/llvm/llvm-project/pull/72389 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Introduce APINotes in Clang Sema and Frontend (PR #72907)
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/72907 This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This adds the initial Clang APINotes infrastructure to Clang Sema and Clang Frontend. There will shortly be a follow-up patch with the actual usages of this API. I'm splitting these changes into separate PRs to keep the diffs easier to review. >From 10bb536d577e18cc210b15df2746b1af17e8d9b2 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 19:13:39 + Subject: [PATCH 1/2] [APINotes] Introduce APINotes in Sema This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This adds the initial Clang APINotes infrastructure to Clang Sema. --- clang/include/clang/Sema/Sema.h | 2 ++ clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/Sema.cpp | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 63a9f9d4cffe2f2..e9872cdeb0b2522 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_SEMA_SEMA_H #define LLVM_CLANG_SEMA_SEMA_H +#include "clang/APINotes/APINotesManager.h" #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTFwd.h" #include "clang/AST/Attr.h" @@ -408,6 +409,7 @@ class Sema final { ASTConsumer &Consumer; DiagnosticsEngine &Diags; SourceManager &SourceMgr; + api_notes::APINotesManager APINotes; /// Flag indicating whether or not to collect detailed statistics. bool CollectStats; diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index d3d403c1d5d79ef..1856a88e9a3271a 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -74,6 +74,7 @@ add_clang_library(clangSema ClangDriverOptions LINK_LIBS + clangAPINotes clangAST clangAnalysis clangBasic diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d7d8d2eaa37e1d6..9771aaa2f3b0371 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -191,7 +191,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, : ExternalSource(nullptr), CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - CollectStats(false), CodeCompleter(CodeCompleter), CurContext(nullptr), + APINotes(SourceMgr, LangOpts), CollectStats(false), + CodeCompleter(CodeCompleter), CurContext(nullptr), OriginalLexicalContext(nullptr), MSStructPragmaOn(false), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), >From b8421b0570cc634e205e5b06d10997a802d5dd76 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 19:23:37 + Subject: [PATCH 2/2] [APINotes] Introduce APINotes in Frontend This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This adds the initial Clang APINotes infrastructure to Clang Frontend. --- clang/include/clang/Frontend/CompilerInstance.h | 5 + clang/lib/Frontend/CMakeLists.txt | 1 + clang/lib/Frontend/CompilerInstance.cpp | 4 3 files changed, 10 insertions(+) diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index d26a452cf94cc3b..ac2f940769fbe90 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -304,6 +304,11 @@ class CompilerInstance : public ModuleLoader { return Invocation->getHeaderSearchOptsPtr(); } + APINotesOptions &getAPINotesOpts() { return Invocation->getAPINotesOpts(); } + const APINotesOptions &getAPINotesOpts() const { +return Invocation->getAPINotesOpts(); + } + LangOptions &getLangOpts() { return Invocation->getLangOpts(); } const LangOptions &getLangOpts() const { return Invocation->getLangOpts(); } diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt index 1e5f0a859dfd568..a91666720884591 100644 --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -48,6 +48,7 @@ add_clang_library(clangFrontend intrinsics_gen LINK_LIBS + clangAPINotes clangAST clangBasic clangDriver diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index d749195585eca5b..be5b38d6110fc3b 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -747,6 +747,10 @@ void CompilerInstance::createSema(Trans
[clang] [APINotes] Introduce APINotes infrastructure in Clang Sema and Frontend (PR #72907)
https://github.com/egorzhdan edited https://github.com/llvm/llvm-project/pull/72907 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Introduce APINotes infrastructure in Clang Sema and Frontend (PR #72907)
egorzhdan wrote: The clang-format failure is unrelated to this patch. https://github.com/llvm/llvm-project/pull/72907 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Introduce APINotes infrastructure in Clang Sema and Frontend (PR #72907)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/72907 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/73017 This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This is the largest chunk of the API Notes functionality in the upstreaming process. I will soon submit a follow-up patch to actually enable usage of this functionality by having a Clang driver flag that enables API Notes, along with tests. (it might be easier to review commit-by-commit) >From ae8c604e9333b1ea54fc6e80134bdba948eeecb7 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 18:03:18 + Subject: [PATCH 1/4] [APINotes] Upstream attributes that are created implicitly from APINotes --- clang/include/clang/Basic/Attr.td | 46 ++- clang/lib/Sema/SemaDeclAttr.cpp | 34 ++--- clang/lib/Serialization/ASTReaderDecl.cpp | 2 + clang/utils/TableGen/ClangAttrEmitter.cpp | 26 - 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c2fbdfc66c540d6..acfb75a3dee3e7a 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -301,6 +301,9 @@ class VariadicEnumArgument values, bit IsExternalType = isExternalType; } +// Represents an attribute wrapped by another attribute. +class AttrArgument : Argument; + // This handles one spelling of an attribute. class Spelling { string Name = name; @@ -2257,7 +2260,7 @@ def ObjCBridgeRelated : InheritableAttr { def NSErrorDomain : InheritableAttr { let Spellings = [GNU<"ns_error_domain">]; let Subjects = SubjectList<[Enum], ErrorDiag>; - let Args = [DeclArgument]; + let Args = [IdentifierArgument<"ErrorDomain">]; let Documentation = [NSErrorDomainDocs]; } @@ -2593,6 +2596,22 @@ def SwiftError : InheritableAttr { let Documentation = [SwiftErrorDocs]; } +def SwiftImportAsNonGeneric : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftImportPropertyAsAccessors : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + def SwiftName : InheritableAttr { let Spellings = [GNU<"swift_name">]; let Args = [StringArgument<"Name">]; @@ -2614,6 +2633,31 @@ def SwiftPrivate : InheritableAttr { let SimpleHandler = 1; } +def SwiftVersioned : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftVersionedRemoval : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; + let AdditionalMembers = [{ +attr::Kind getAttrKindToRemove() const { + return static_cast(getRawKind()); +} + }]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index fd778793346f502..8552b28e51acd97 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6210,29 +6210,35 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } -static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *E = AL.getArgAsExpr(0); - auto Loc = E ? E->getBeginLoc() : AL.getLoc(); - - auto *DRE = dyn_cast(AL.getArgAsExpr(0)); - if (!DRE) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { +S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; return; } - auto *VD = dyn_cast(DRE->getDecl()); - if (!VD) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + IdentifierLoc *IdentLoc = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!IdentLoc || !IdentLoc->Ident) { +// Try to locate the argument directly. +SourceLocation Loc = Attr.getLoc(); +if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) + Loc = Attr.getArgAsExpr(0)->getBeginLoc(); + +S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; return; } - if (!
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/73017 >From ae8c604e9333b1ea54fc6e80134bdba948eeecb7 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 18:03:18 + Subject: [PATCH 1/4] [APINotes] Upstream attributes that are created implicitly from APINotes --- clang/include/clang/Basic/Attr.td | 46 ++- clang/lib/Sema/SemaDeclAttr.cpp | 34 ++--- clang/lib/Serialization/ASTReaderDecl.cpp | 2 + clang/utils/TableGen/ClangAttrEmitter.cpp | 26 - 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c2fbdfc66c540d6..acfb75a3dee3e7a 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -301,6 +301,9 @@ class VariadicEnumArgument values, bit IsExternalType = isExternalType; } +// Represents an attribute wrapped by another attribute. +class AttrArgument : Argument; + // This handles one spelling of an attribute. class Spelling { string Name = name; @@ -2257,7 +2260,7 @@ def ObjCBridgeRelated : InheritableAttr { def NSErrorDomain : InheritableAttr { let Spellings = [GNU<"ns_error_domain">]; let Subjects = SubjectList<[Enum], ErrorDiag>; - let Args = [DeclArgument]; + let Args = [IdentifierArgument<"ErrorDomain">]; let Documentation = [NSErrorDomainDocs]; } @@ -2593,6 +2596,22 @@ def SwiftError : InheritableAttr { let Documentation = [SwiftErrorDocs]; } +def SwiftImportAsNonGeneric : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftImportPropertyAsAccessors : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + def SwiftName : InheritableAttr { let Spellings = [GNU<"swift_name">]; let Args = [StringArgument<"Name">]; @@ -2614,6 +2633,31 @@ def SwiftPrivate : InheritableAttr { let SimpleHandler = 1; } +def SwiftVersioned : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftVersionedRemoval : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; + let AdditionalMembers = [{ +attr::Kind getAttrKindToRemove() const { + return static_cast(getRawKind()); +} + }]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index fd778793346f502..8552b28e51acd97 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6210,29 +6210,35 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } -static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *E = AL.getArgAsExpr(0); - auto Loc = E ? E->getBeginLoc() : AL.getLoc(); - - auto *DRE = dyn_cast(AL.getArgAsExpr(0)); - if (!DRE) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { +S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; return; } - auto *VD = dyn_cast(DRE->getDecl()); - if (!VD) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + IdentifierLoc *IdentLoc = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!IdentLoc || !IdentLoc->Ident) { +// Try to locate the argument directly. +SourceLocation Loc = Attr.getLoc(); +if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) + Loc = Attr.getArgAsExpr(0)->getBeginLoc(); + +S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; return; } - if (!isNSStringType(VD->getType(), S.Context) && - !isCFStringType(VD->getType(), S.Context)) { -S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + // Verify that the identifier is a valid decl in the C decl namespace. + LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(), + Sema::LookupNameKind::LookupOrdinaryName); + if (!S.LookupName(Result, S.TUScope) || !Result.getAsSingle()) { +S.Diag(IdentLoc->Loc, d
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/73017 >From ae8c604e9333b1ea54fc6e80134bdba948eeecb7 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 18:03:18 + Subject: [PATCH 1/4] [APINotes] Upstream attributes that are created implicitly from APINotes --- clang/include/clang/Basic/Attr.td | 46 ++- clang/lib/Sema/SemaDeclAttr.cpp | 34 ++--- clang/lib/Serialization/ASTReaderDecl.cpp | 2 + clang/utils/TableGen/ClangAttrEmitter.cpp | 26 - 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c2fbdfc66c540d6..acfb75a3dee3e7a 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -301,6 +301,9 @@ class VariadicEnumArgument values, bit IsExternalType = isExternalType; } +// Represents an attribute wrapped by another attribute. +class AttrArgument : Argument; + // This handles one spelling of an attribute. class Spelling { string Name = name; @@ -2257,7 +2260,7 @@ def ObjCBridgeRelated : InheritableAttr { def NSErrorDomain : InheritableAttr { let Spellings = [GNU<"ns_error_domain">]; let Subjects = SubjectList<[Enum], ErrorDiag>; - let Args = [DeclArgument]; + let Args = [IdentifierArgument<"ErrorDomain">]; let Documentation = [NSErrorDomainDocs]; } @@ -2593,6 +2596,22 @@ def SwiftError : InheritableAttr { let Documentation = [SwiftErrorDocs]; } +def SwiftImportAsNonGeneric : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftImportPropertyAsAccessors : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + def SwiftName : InheritableAttr { let Spellings = [GNU<"swift_name">]; let Args = [StringArgument<"Name">]; @@ -2614,6 +2633,31 @@ def SwiftPrivate : InheritableAttr { let SimpleHandler = 1; } +def SwiftVersioned : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftVersionedRemoval : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; + let AdditionalMembers = [{ +attr::Kind getAttrKindToRemove() const { + return static_cast(getRawKind()); +} + }]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index fd778793346f502..8552b28e51acd97 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6210,29 +6210,35 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } -static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *E = AL.getArgAsExpr(0); - auto Loc = E ? E->getBeginLoc() : AL.getLoc(); - - auto *DRE = dyn_cast(AL.getArgAsExpr(0)); - if (!DRE) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { +S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; return; } - auto *VD = dyn_cast(DRE->getDecl()); - if (!VD) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + IdentifierLoc *IdentLoc = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!IdentLoc || !IdentLoc->Ident) { +// Try to locate the argument directly. +SourceLocation Loc = Attr.getLoc(); +if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) + Loc = Attr.getArgAsExpr(0)->getBeginLoc(); + +S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; return; } - if (!isNSStringType(VD->getType(), S.Context) && - !isCFStringType(VD->getType(), S.Context)) { -S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + // Verify that the identifier is a valid decl in the C decl namespace. + LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(), + Sema::LookupNameKind::LookupOrdinaryName); + if (!S.LookupName(Result, S.TUScope) || !Result.getAsSingle()) { +S.Diag(IdentLoc->Loc, d
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/73017 >From ae8c604e9333b1ea54fc6e80134bdba948eeecb7 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 18:03:18 + Subject: [PATCH 1/4] [APINotes] Upstream attributes that are created implicitly from APINotes --- clang/include/clang/Basic/Attr.td | 46 ++- clang/lib/Sema/SemaDeclAttr.cpp | 34 ++--- clang/lib/Serialization/ASTReaderDecl.cpp | 2 + clang/utils/TableGen/ClangAttrEmitter.cpp | 26 - 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c2fbdfc66c540d6..acfb75a3dee3e7a 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -301,6 +301,9 @@ class VariadicEnumArgument values, bit IsExternalType = isExternalType; } +// Represents an attribute wrapped by another attribute. +class AttrArgument : Argument; + // This handles one spelling of an attribute. class Spelling { string Name = name; @@ -2257,7 +2260,7 @@ def ObjCBridgeRelated : InheritableAttr { def NSErrorDomain : InheritableAttr { let Spellings = [GNU<"ns_error_domain">]; let Subjects = SubjectList<[Enum], ErrorDiag>; - let Args = [DeclArgument]; + let Args = [IdentifierArgument<"ErrorDomain">]; let Documentation = [NSErrorDomainDocs]; } @@ -2593,6 +2596,22 @@ def SwiftError : InheritableAttr { let Documentation = [SwiftErrorDocs]; } +def SwiftImportAsNonGeneric : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftImportPropertyAsAccessors : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + def SwiftName : InheritableAttr { let Spellings = [GNU<"swift_name">]; let Args = [StringArgument<"Name">]; @@ -2614,6 +2633,31 @@ def SwiftPrivate : InheritableAttr { let SimpleHandler = 1; } +def SwiftVersioned : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftVersionedRemoval : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; + let AdditionalMembers = [{ +attr::Kind getAttrKindToRemove() const { + return static_cast(getRawKind()); +} + }]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index fd778793346f502..8552b28e51acd97 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6210,29 +6210,35 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } -static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *E = AL.getArgAsExpr(0); - auto Loc = E ? E->getBeginLoc() : AL.getLoc(); - - auto *DRE = dyn_cast(AL.getArgAsExpr(0)); - if (!DRE) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { +S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; return; } - auto *VD = dyn_cast(DRE->getDecl()); - if (!VD) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + IdentifierLoc *IdentLoc = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!IdentLoc || !IdentLoc->Ident) { +// Try to locate the argument directly. +SourceLocation Loc = Attr.getLoc(); +if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) + Loc = Attr.getArgAsExpr(0)->getBeginLoc(); + +S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; return; } - if (!isNSStringType(VD->getType(), S.Context) && - !isCFStringType(VD->getType(), S.Context)) { -S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + // Verify that the identifier is a valid decl in the C decl namespace. + LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(), + Sema::LookupNameKind::LookupOrdinaryName); + if (!S.LookupName(Result, S.TUScope) || !Result.getAsSingle()) { +S.Diag(IdentLoc->Loc, d
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/73017 >From d7d8e8520681b6a71fda9848b18828cff8ed7415 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 18:03:18 + Subject: [PATCH 1/4] [APINotes] Upstream attributes that are created implicitly from APINotes --- clang/include/clang/Basic/Attr.td | 46 ++- clang/lib/Sema/SemaDeclAttr.cpp | 34 ++--- clang/lib/Serialization/ASTReaderDecl.cpp | 2 + clang/utils/TableGen/ClangAttrEmitter.cpp | 26 - 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c2fbdfc66c540d6..a9ad6c878306ad3 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -301,6 +301,9 @@ class VariadicEnumArgument values, bit IsExternalType = isExternalType; } +// Represents an attribute wrapped by another attribute. +class AttrArgument : Argument; + // This handles one spelling of an attribute. class Spelling { string Name = name; @@ -2257,7 +2260,7 @@ def ObjCBridgeRelated : InheritableAttr { def NSErrorDomain : InheritableAttr { let Spellings = [GNU<"ns_error_domain">]; let Subjects = SubjectList<[Enum], ErrorDiag>; - let Args = [DeclArgument]; + let Args = [IdentifierArgument<"ErrorDomain">]; let Documentation = [NSErrorDomainDocs]; } @@ -2593,6 +2596,22 @@ def SwiftError : InheritableAttr { let Documentation = [SwiftErrorDocs]; } +def SwiftImportAsNonGeneric : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftImportPropertyAsAccessors : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + def SwiftName : InheritableAttr { let Spellings = [GNU<"swift_name">]; let Args = [StringArgument<"Name">]; @@ -2614,6 +2633,31 @@ def SwiftPrivate : InheritableAttr { let SimpleHandler = 1; } +def SwiftVersioned : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftVersionedRemoval : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; + let AdditionalMembers = [{ +attr::Kind getAttrKindToRemove() const { + return static_cast(getRawKind()); +} + }]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index fd778793346f502..8552b28e51acd97 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6210,29 +6210,35 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } -static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *E = AL.getArgAsExpr(0); - auto Loc = E ? E->getBeginLoc() : AL.getLoc(); - - auto *DRE = dyn_cast(AL.getArgAsExpr(0)); - if (!DRE) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { +S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; return; } - auto *VD = dyn_cast(DRE->getDecl()); - if (!VD) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + IdentifierLoc *IdentLoc = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!IdentLoc || !IdentLoc->Ident) { +// Try to locate the argument directly. +SourceLocation Loc = Attr.getLoc(); +if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) + Loc = Attr.getArgAsExpr(0)->getBeginLoc(); + +S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; return; } - if (!isNSStringType(VD->getType(), S.Context) && - !isCFStringType(VD->getType(), S.Context)) { -S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + // Verify that the identifier is a valid decl in the C decl namespace. + LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(), + Sema::LookupNameKind::LookupOrdinaryName); + if (!S.LookupName(Result, S.TUScope) || !Result.getAsSingle()) { +S.Diag(IdentLoc->Loc, di
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/73017 >From cea6998f68ffca08edb8bed555df093c8fe48d1c Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 18:03:18 + Subject: [PATCH 1/4] [APINotes] Upstream attributes that are created implicitly from APINotes --- clang/include/clang/Basic/Attr.td | 46 ++- clang/lib/Sema/SemaDeclAttr.cpp | 34 ++--- clang/lib/Serialization/ASTReaderDecl.cpp | 2 + clang/test/Sema/ns_error_enum.m | 3 +- clang/utils/TableGen/ClangAttrEmitter.cpp | 26 - 5 files changed, 93 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c2fbdfc66c540d6..a9ad6c878306ad3 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -301,6 +301,9 @@ class VariadicEnumArgument values, bit IsExternalType = isExternalType; } +// Represents an attribute wrapped by another attribute. +class AttrArgument : Argument; + // This handles one spelling of an attribute. class Spelling { string Name = name; @@ -2257,7 +2260,7 @@ def ObjCBridgeRelated : InheritableAttr { def NSErrorDomain : InheritableAttr { let Spellings = [GNU<"ns_error_domain">]; let Subjects = SubjectList<[Enum], ErrorDiag>; - let Args = [DeclArgument]; + let Args = [IdentifierArgument<"ErrorDomain">]; let Documentation = [NSErrorDomainDocs]; } @@ -2593,6 +2596,22 @@ def SwiftError : InheritableAttr { let Documentation = [SwiftErrorDocs]; } +def SwiftImportAsNonGeneric : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftImportPropertyAsAccessors : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + def SwiftName : InheritableAttr { let Spellings = [GNU<"swift_name">]; let Args = [StringArgument<"Name">]; @@ -2614,6 +2633,31 @@ def SwiftPrivate : InheritableAttr { let SimpleHandler = 1; } +def SwiftVersioned : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftVersionedRemoval : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; + let AdditionalMembers = [{ +attr::Kind getAttrKindToRemove() const { + return static_cast(getRawKind()); +} + }]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index fd778793346f502..8552b28e51acd97 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6210,29 +6210,35 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } -static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *E = AL.getArgAsExpr(0); - auto Loc = E ? E->getBeginLoc() : AL.getLoc(); - - auto *DRE = dyn_cast(AL.getArgAsExpr(0)); - if (!DRE) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { +S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; return; } - auto *VD = dyn_cast(DRE->getDecl()); - if (!VD) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + IdentifierLoc *IdentLoc = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!IdentLoc || !IdentLoc->Ident) { +// Try to locate the argument directly. +SourceLocation Loc = Attr.getLoc(); +if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) + Loc = Attr.getArgAsExpr(0)->getBeginLoc(); + +S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; return; } - if (!isNSStringType(VD->getType(), S.Context) && - !isCFStringType(VD->getType(), S.Context)) { -S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + // Verify that the identifier is a valid decl in the C decl namespace. + LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(), + Sema::LookupNameKind::LookupOrdinaryName); + if (!S.LookupName(Result, S.TUScope) || !Re
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/73120 This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes >From 41f0d8ce31e656288cb5753c372829fcf4bb80bc Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 22 Nov 2023 13:54:04 + Subject: [PATCH] [APINotes] Upstream Driver and Frontend options that enable API Notes This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Driver/Options.td | 13 + clang/lib/Driver/ToolChains/Clang.cpp | 11 +++ clang/lib/Frontend/CompilerInstance.cpp | 8 clang/lib/Frontend/CompilerInvocation.cpp | 23 +++ 5 files changed, 56 insertions(+) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index cd77b22bf3ace4b..c3d5399905a3fda 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -405,6 +405,7 @@ LANGOPT(XLPragmaPack, 1, 0, "IBM XL #pragma pack handling") LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST") LANGOPT(APINotes, 1, 0, "use external API notes") +LANGOPT(APINotesModules, 1, 0, "use module-based external API notes") LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " "field padding (0: none, 1:least " diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b2f2bcb6ac37910..ff2e4572ec4305f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1754,6 +1754,19 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +defm apinotes : BoolOption<"f", "apinotes", + LangOpts<"APINotes">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption, CC1Option], " external API notes support">>, + Group; +defm apinotes_modules : BoolOption<"f", "apinotes-modules", + LangOpts<"APINotesModules">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption, CC1Option], + " module-based external API notes support">>, + Group; def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">, Group, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6dec117aed1056b..575ba57eef758db 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6720,6 +6720,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new); + if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false) || + Args.hasArg(options::OPT_iapinotes_modules)) { +if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false)) + CmdArgs.push_back("-fapinotes"); +if (Args.hasFlag(options::OPT_fapinotes_modules, + options::OPT_fno_apinotes_modules, false)) + CmdArgs.push_back("-fapinotes-modules"); + +Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version); + } + // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, TC.IsBlocksDefault()) || diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index be5b38d6110fc3b..f9f839b3d391292 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -756,6 +756,14 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind, TheSema->addExternalSource(ExternalSemaSrc.get()); ExternalSemaSrc->InitializeSema(*TheSema); } + + // If we're building a module and are supposed to load API notes, + // notify the API notes manager. + if (auto currentModule = getPreprocessor().getCurrentModule()) { +(void)TheSema->APINotes.loadCurrentModuleAPINotes( +currentModule, getLangOpts().APINotesModules, +getAPINotesOpts().ModuleSearchPaths); + } } // Output Files diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 3f4ca02539080d0..3b92cc1281f9e0e 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3267,6 +3267,16 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, return D
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/73120 >From 43cbb211490efdd2449ebef9847ce44eab02d3e4 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 22 Nov 2023 13:54:04 + Subject: [PATCH] [APINotes] Upstream Driver and Frontend options that enable API Notes This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Driver/Options.td | 12 clang/lib/Driver/ToolChains/Clang.cpp | 13 + clang/lib/Frontend/CompilerInstance.cpp | 8 clang/lib/Frontend/CompilerInvocation.cpp | 23 +++ 5 files changed, 57 insertions(+) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index cd77b22bf3ace4b..c3d5399905a3fda 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -405,6 +405,7 @@ LANGOPT(XLPragmaPack, 1, 0, "IBM XL #pragma pack handling") LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST") LANGOPT(APINotes, 1, 0, "use external API notes") +LANGOPT(APINotesModules, 1, 0, "use module-based external API notes") LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " "field padding (0: none, 1:least " diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b2f2bcb6ac37910..9191ccd2a66ac4a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1754,6 +1754,18 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +defm apinotes : BoolOption<"f", "apinotes", +LangOpts<"APINotes">, DefaultFalse, +PosFlag, +NegFlag, +BothFlags<[], [ClangOption, CC1Option], "external API notes support">>, +Group; +defm apinotes_modules : BoolOption<"f", "apinotes-modules", +LangOpts<"APINotesModules">, DefaultFalse, +PosFlag, +NegFlag, +BothFlags<[], [ClangOption, CC1Option], "module-based external API notes support">>, +Group; def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">, Group, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6dec117aed1056b..972bdb37e45209b 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6720,6 +6720,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new); + if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false) || + Args.hasFlag(options::OPT_fapinotes_modules, + options::OPT_fno_apinotes_modules, false) || + Args.hasArg(options::OPT_iapinotes_modules)) { +if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false)) + CmdArgs.push_back("-fapinotes"); +if (Args.hasFlag(options::OPT_fapinotes_modules, + options::OPT_fno_apinotes_modules, false)) + CmdArgs.push_back("-fapinotes-modules"); + +Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version); + } + // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, TC.IsBlocksDefault()) || diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index be5b38d6110fc3b..e5f8c0746a99dd4 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -756,6 +756,14 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind, TheSema->addExternalSource(ExternalSemaSrc.get()); ExternalSemaSrc->InitializeSema(*TheSema); } + + // If we're building a module and are supposed to load API notes, + // notify the API notes manager. + if (auto *currentModule = getPreprocessor().getCurrentModule()) { +(void)TheSema->APINotes.loadCurrentModuleAPINotes( +currentModule, getLangOpts().APINotesModules, +getAPINotesOpts().ModuleSearchPaths); + } } // Output Files diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 3f4ca02539080d0..3b92cc1281f9e0e 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3267,6 +3267,16 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, return Diags.getNumErrors() == NumErrorsBefore; } +sta
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
@@ -1754,6 +1754,19 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +defm apinotes : BoolOption<"f", "apinotes", + LangOpts<"APINotes">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption, CC1Option], " external API notes support">>, + Group; egorzhdan wrote: Done https://github.com/llvm/llvm-project/pull/73120 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
@@ -1754,6 +1754,19 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +defm apinotes : BoolOption<"f", "apinotes", + LangOpts<"APINotes">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption, CC1Option], " external API notes support">>, egorzhdan wrote: Doesn't seem to be intentional, removed it. https://github.com/llvm/llvm-project/pull/73120 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
@@ -6720,6 +6720,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new); + if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false) || + Args.hasArg(options::OPT_iapinotes_modules)) { egorzhdan wrote: My mistake, the outer `if` condition became wrong during my refactoring attempt. Fixed it. https://github.com/llvm/llvm-project/pull/73120 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
@@ -756,6 +756,14 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind, TheSema->addExternalSource(ExternalSemaSrc.get()); ExternalSemaSrc->InitializeSema(*TheSema); } + + // If we're building a module and are supposed to load API notes, + // notify the API notes manager. + if (auto currentModule = getPreprocessor().getCurrentModule()) { egorzhdan wrote: Alright, done https://github.com/llvm/llvm-project/pull/73120 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesReader (PR #66769)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/66769 >From e165261eb5baa8c2660ac8b2319cb96d13578572 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Tue, 19 Sep 2023 13:42:16 +0100 Subject: [PATCH] [APINotes] Upstream APINotesReader This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- clang/include/clang/APINotes/APINotesReader.h | 200 ++ clang/include/clang/APINotes/Types.h |8 +- clang/lib/APINotes/APINotesReader.cpp | 2048 + clang/lib/APINotes/CMakeLists.txt |3 + 4 files changed, 2252 insertions(+), 7 deletions(-) create mode 100644 clang/include/clang/APINotes/APINotesReader.h create mode 100644 clang/lib/APINotes/APINotesReader.cpp diff --git a/clang/include/clang/APINotes/APINotesReader.h b/clang/include/clang/APINotes/APINotesReader.h new file mode 100644 index 000..1c5aab09595509e --- /dev/null +++ b/clang/include/clang/APINotes/APINotesReader.h @@ -0,0 +1,200 @@ +//===--- APINotesReader.h - API Notes Reader *- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// This file defines the \c APINotesReader class that reads source API notes +// data providing additional information about source code as a separate input, +// such as the non-nil/nilable annotations for method parameters. +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_READER_H +#define LLVM_CLANG_APINOTES_READER_H + +#include "clang/APINotes/Types.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VersionTuple.h" +#include + +namespace clang { +namespace api_notes { + +/// A class that reads API notes data from a binary file that was written by +/// the \c APINotesWriter. +class APINotesReader { + class Implementation; + std::unique_ptr Implementation; + + APINotesReader(llvm::MemoryBuffer *InputBuffer, + llvm::VersionTuple SwiftVersion, bool &Failed); + +public: + /// Create a new API notes reader from the given member buffer, which + /// contains the contents of a binary API notes file. + /// + /// \returns the new API notes reader, or null if an error occurred. + static std::unique_ptr + Create(std::unique_ptr InputBuffer, + llvm::VersionTuple SwiftVersion); + + ~APINotesReader(); + + APINotesReader(const APINotesReader &) = delete; + APINotesReader &operator=(const APINotesReader &) = delete; + + /// Captures the completed versioned information for a particular part of + /// API notes, including both unversioned API notes and each versioned API + /// note for that particular entity. + template class VersionedInfo { +/// The complete set of results. +llvm::SmallVector, 1> Results; + +/// The index of the result that is the "selected" set based on the desired +/// Swift version, or null if nothing matched. +std::optional Selected; + + public: +/// Form an empty set of versioned information. +VersionedInfo(std::nullopt_t) : Selected(std::nullopt) {} + +/// Form a versioned info set given the desired version and a set of +/// results. +VersionedInfo( +llvm::VersionTuple Version, +llvm::SmallVector, 1> Results); + +/// Retrieve the selected index in the result set. +std::optional getSelected() const { return Selected; } + +/// Return the number of versioned results we know about. +unsigned size() const { return Results.size(); } + +/// Access all versioned results. +const std::pair *begin() const { + assert(!Results.empty()); + return Results.begin(); +} +const std::pair *end() const { + return Results.end(); +} + +/// Access a specific versioned result. +const std::pair &operator[](unsigned index) const { + assert(index < Results.size()); + return Results[index]; +} + }; + + /// Look for the context ID of the given Objective-C class. + /// + /// \param Name The name of the class we're looking for. + /// + /// \returns The ID, if known. + std::optional lookupObjCClassID(llvm::StringRef Name); + + /// Look for information regarding the given Objective-C class. + /// + /// \param Name The name of the class we're looking for. + /// + /// \returns The information about the class, if known. + VersionedInfo lookupObjCClassInfo(llvm::StringRef Name); + + /// Look for the context ID of the given Objective-C protocol. + /// + /// \param Name The name of the protocol we're looking for. + /// + /// \returns The ID of the protocol, if known. + std::optional lookupObjCPro
[clang] [APINotes] Upstream APINotesReader (PR #66769)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/66769 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesOptions (PR #70827)
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/70827 This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This adds the first compiler options related to API Notes to the upstream Clang: `-iapinotes-modules` and `-fapinotes-swift-version=`. However, this does not add the `-fapinotes` flag that enables API Notes, since the feature is not fully functional yet. >From 368f2b2580ef7ba8777020c40edcbb3b08c5b9ad Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Tue, 31 Oct 2023 16:39:45 + Subject: [PATCH] [APINotes] Upstream APINotesOptions This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This adds the first compiler options related to API Notes to the upstream Clang: `-iapinotes-modules` and `-fapinotes-swift-version=`. However, this does not add the `-fapinotes` flag that enables API Notes, since the feature is not fully functional yet. --- .../include/clang/APINotes/APINotesOptions.h | 34 +++ clang/include/clang/Driver/Options.td | 7 .../clang/Frontend/CompilerInvocation.h | 6 clang/lib/Frontend/CompilerInvocation.cpp | 12 +++ 4 files changed, 59 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesOptions.h diff --git a/clang/include/clang/APINotes/APINotesOptions.h b/clang/include/clang/APINotes/APINotesOptions.h new file mode 100644 index 000..e8b8a9ed2261fa1 --- /dev/null +++ b/clang/include/clang/APINotes/APINotesOptions.h @@ -0,0 +1,34 @@ +//===--- APINotesOptions.h --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESOPTIONS_H +#define LLVM_CLANG_APINOTES_APINOTESOPTIONS_H + +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +/// Tracks various options which control how API notes are found and handled. +class APINotesOptions { +public: + /// The Swift version which should be used for API notes. + llvm::VersionTuple SwiftVersion; + + /// The set of search paths where we API notes can be found for particular + /// modules. + /// + /// The API notes in this directory are stored as .apinotes, and + /// are only applied when building the module . + std::vector ModuleSearchPaths; +}; + +} // namespace clang + +#endif // LLVM_CLANG_APINOTES_APINOTESOPTIONS_H diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8b730e0f7ecd84..940f63dd5736750 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1733,6 +1733,10 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">, + Group, Visibility<[ClangOption, CC1Option]>, + MetaVarName<"">, + HelpText<"Specify the Swift version to use when filtering API notes">; defm addrsig : BoolFOption<"addrsig", CodeGenOpts<"Addrsig">, DefaultFalse, @@ -4129,6 +4133,9 @@ def ibuiltininc : Flag<["-"], "ibuiltininc">, Group, def index_header_map : Flag<["-"], "index-header-map">, Visibility<[ClangOption, CC1Option]>, HelpText<"Make the next included directory (-I or -F) an indexer header map">; +def iapinotes_modules : JoinedOrSeparate<["-"], "iapinotes-modules">, Group, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Add directory to the API notes search path referenced by module name">, MetaVarName<"">; def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Add directory to AFTER include search path">; diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 45e263e7bc76822..d9c757a8a156861 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H #define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H +#include "clang/APINotes/APINotesOptions.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileSystemOptions.h" @@ -92,6 +93,9 @@ class CompilerInvocationBase { std::shared_ptr MigratorOpts; + /// Options controlling API notes. + std::shared_ptr APINotesOpts; + /// Op
[clang] [APINotes] Upstream APINotesOptions (PR #70827)
egorzhdan wrote: The clang-format failure is not related to the changes in this PR. https://github.com/llvm/llvm-project/pull/70827 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesOptions (PR #70827)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/70827 >From 552995265316fd04bd73148fce010aa3cd0368f5 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Tue, 31 Oct 2023 16:39:45 + Subject: [PATCH] [APINotes] Upstream APINotesOptions This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This adds the first compiler options related to API Notes to the upstream Clang: `-iapinotes-modules` and `-fapinotes-swift-version=`. However, this does not add the `-fapinotes` flag that enables API Notes, since the feature is not fully functional yet. --- .../include/clang/APINotes/APINotesOptions.h | 34 +++ clang/include/clang/Driver/Options.td | 7 .../clang/Frontend/CompilerInvocation.h | 6 clang/lib/Frontend/CompilerInvocation.cpp | 12 +++ 4 files changed, 59 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesOptions.h diff --git a/clang/include/clang/APINotes/APINotesOptions.h b/clang/include/clang/APINotes/APINotesOptions.h new file mode 100644 index 000..e8b8a9ed2261fa1 --- /dev/null +++ b/clang/include/clang/APINotes/APINotesOptions.h @@ -0,0 +1,34 @@ +//===--- APINotesOptions.h --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESOPTIONS_H +#define LLVM_CLANG_APINOTES_APINOTESOPTIONS_H + +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +/// Tracks various options which control how API notes are found and handled. +class APINotesOptions { +public: + /// The Swift version which should be used for API notes. + llvm::VersionTuple SwiftVersion; + + /// The set of search paths where we API notes can be found for particular + /// modules. + /// + /// The API notes in this directory are stored as .apinotes, and + /// are only applied when building the module . + std::vector ModuleSearchPaths; +}; + +} // namespace clang + +#endif // LLVM_CLANG_APINOTES_APINOTESOPTIONS_H diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8b730e0f7ecd84..940f63dd5736750 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1733,6 +1733,10 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">, + Group, Visibility<[ClangOption, CC1Option]>, + MetaVarName<"">, + HelpText<"Specify the Swift version to use when filtering API notes">; defm addrsig : BoolFOption<"addrsig", CodeGenOpts<"Addrsig">, DefaultFalse, @@ -4129,6 +4133,9 @@ def ibuiltininc : Flag<["-"], "ibuiltininc">, Group, def index_header_map : Flag<["-"], "index-header-map">, Visibility<[ClangOption, CC1Option]>, HelpText<"Make the next included directory (-I or -F) an indexer header map">; +def iapinotes_modules : JoinedOrSeparate<["-"], "iapinotes-modules">, Group, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Add directory to the API notes search path referenced by module name">, MetaVarName<"">; def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Add directory to AFTER include search path">; diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 45e263e7bc76822..d9c757a8a156861 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H #define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H +#include "clang/APINotes/APINotesOptions.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileSystemOptions.h" @@ -92,6 +93,9 @@ class CompilerInvocationBase { std::shared_ptr MigratorOpts; + /// Options controlling API notes. + std::shared_ptr APINotesOpts; + /// Options controlling IRgen and the backend. std::shared_ptr CodeGenOpts; @@ -131,6 +135,7 @@ class CompilerInvocationBase { const PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; } const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; } const MigratorOptions &getMigratorOpts() const { return *MigratorOpts; } + const APINotesOptions &getAPINotesOpts() const { return *APINotesOpts; }
[clang] [APINotes] Upstream APINotesOptions (PR #70827)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/70827 >From 573e7ea751af1be41b3c984e7dc6b334f0ac0142 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Tue, 31 Oct 2023 16:39:45 + Subject: [PATCH] [APINotes] Upstream APINotesOptions This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This adds the first compiler options related to API Notes to the upstream Clang: `-iapinotes-modules` and `-fapinotes-swift-version=`. However, this does not add the `-fapinotes` flag that enables API Notes, since the feature is not fully functional yet. --- .../include/clang/APINotes/APINotesOptions.h | 34 +++ clang/include/clang/Driver/Options.td | 7 .../clang/Frontend/CompilerInvocation.h | 6 clang/lib/Frontend/CompilerInvocation.cpp | 12 +++ 4 files changed, 59 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesOptions.h diff --git a/clang/include/clang/APINotes/APINotesOptions.h b/clang/include/clang/APINotes/APINotesOptions.h new file mode 100644 index 000..e8b8a9ed2261fa1 --- /dev/null +++ b/clang/include/clang/APINotes/APINotesOptions.h @@ -0,0 +1,34 @@ +//===--- APINotesOptions.h --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESOPTIONS_H +#define LLVM_CLANG_APINOTES_APINOTESOPTIONS_H + +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +/// Tracks various options which control how API notes are found and handled. +class APINotesOptions { +public: + /// The Swift version which should be used for API notes. + llvm::VersionTuple SwiftVersion; + + /// The set of search paths where we API notes can be found for particular + /// modules. + /// + /// The API notes in this directory are stored as .apinotes, and + /// are only applied when building the module . + std::vector ModuleSearchPaths; +}; + +} // namespace clang + +#endif // LLVM_CLANG_APINOTES_APINOTESOPTIONS_H diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8b730e0f7ecd84..940f63dd5736750 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1733,6 +1733,10 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">, + Group, Visibility<[ClangOption, CC1Option]>, + MetaVarName<"">, + HelpText<"Specify the Swift version to use when filtering API notes">; defm addrsig : BoolFOption<"addrsig", CodeGenOpts<"Addrsig">, DefaultFalse, @@ -4129,6 +4133,9 @@ def ibuiltininc : Flag<["-"], "ibuiltininc">, Group, def index_header_map : Flag<["-"], "index-header-map">, Visibility<[ClangOption, CC1Option]>, HelpText<"Make the next included directory (-I or -F) an indexer header map">; +def iapinotes_modules : JoinedOrSeparate<["-"], "iapinotes-modules">, Group, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Add directory to the API notes search path referenced by module name">, MetaVarName<"">; def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Add directory to AFTER include search path">; diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 45e263e7bc76822..d9c757a8a156861 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H #define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H +#include "clang/APINotes/APINotesOptions.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileSystemOptions.h" @@ -92,6 +93,9 @@ class CompilerInvocationBase { std::shared_ptr MigratorOpts; + /// Options controlling API notes. + std::shared_ptr APINotesOpts; + /// Options controlling IRgen and the backend. std::shared_ptr CodeGenOpts; @@ -131,6 +135,7 @@ class CompilerInvocationBase { const PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; } const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; } const MigratorOptions &getMigratorOpts() const { return *MigratorOpts; } + const APINotesOptions &getAPINotesOpts() const { return *APINotesOpts; }
[clang] [APINotes] Upstream APINotesOptions (PR #70827)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/70827 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream APINotesOptions (PR #70827)
egorzhdan wrote: ``` 47.207 [1384/8/4064] ASTNodeAPI.json FAILED: tools/clang/lib/Tooling/ASTNodeAPI.json /home/buildbot/worker/as-builder-7/ramdisk/flang-runtime-cuda-clang/build/clang/tools/clang/lib/Tooling/ASTNodeAPI.json ``` Looking into this https://github.com/llvm/llvm-project/pull/70827 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Revert "Revert "[APINotes] Upstream APINotesOptions"" (PR #70975)
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/70975 This re-lands https://github.com/llvm/llvm-project/pull/70827 while preventing the assertion failure that occurred when generating `ASTNodeAPI.json` on non-Apple platforms. >From 07f57b151a455a9a3587bd257bfd9a92889120be Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 1 Nov 2023 19:03:57 + Subject: [PATCH 1/2] Revert "Revert "[APINotes] Upstream APINotesOptions"" This reverts commit 0e06ddf0f6896cfd817a1b97a43b78331e0b1d66. --- .../include/clang/APINotes/APINotesOptions.h | 34 +++ clang/include/clang/Driver/Options.td | 7 .../clang/Frontend/CompilerInvocation.h | 6 clang/lib/Frontend/CompilerInvocation.cpp | 12 +++ 4 files changed, 59 insertions(+) create mode 100644 clang/include/clang/APINotes/APINotesOptions.h diff --git a/clang/include/clang/APINotes/APINotesOptions.h b/clang/include/clang/APINotes/APINotesOptions.h new file mode 100644 index 000..e8b8a9ed2261fa1 --- /dev/null +++ b/clang/include/clang/APINotes/APINotesOptions.h @@ -0,0 +1,34 @@ +//===--- APINotesOptions.h --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_APINOTES_APINOTESOPTIONS_H +#define LLVM_CLANG_APINOTES_APINOTESOPTIONS_H + +#include "llvm/Support/VersionTuple.h" +#include +#include + +namespace clang { + +/// Tracks various options which control how API notes are found and handled. +class APINotesOptions { +public: + /// The Swift version which should be used for API notes. + llvm::VersionTuple SwiftVersion; + + /// The set of search paths where we API notes can be found for particular + /// modules. + /// + /// The API notes in this directory are stored as .apinotes, and + /// are only applied when building the module . + std::vector ModuleSearchPaths; +}; + +} // namespace clang + +#endif // LLVM_CLANG_APINOTES_APINOTESOPTIONS_H diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b1229b2f4562379..fcf6a4b2ccb2369 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1733,6 +1733,10 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">, + Group, Visibility<[ClangOption, CC1Option]>, + MetaVarName<"">, + HelpText<"Specify the Swift version to use when filtering API notes">; defm addrsig : BoolFOption<"addrsig", CodeGenOpts<"Addrsig">, DefaultFalse, @@ -4129,6 +4133,9 @@ def ibuiltininc : Flag<["-"], "ibuiltininc">, Group, def index_header_map : Flag<["-"], "index-header-map">, Visibility<[ClangOption, CC1Option]>, HelpText<"Make the next included directory (-I or -F) an indexer header map">; +def iapinotes_modules : JoinedOrSeparate<["-"], "iapinotes-modules">, Group, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Add directory to the API notes search path referenced by module name">, MetaVarName<"">; def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Add directory to AFTER include search path">; diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 45e263e7bc76822..d9c757a8a156861 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H #define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H +#include "clang/APINotes/APINotesOptions.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileSystemOptions.h" @@ -92,6 +93,9 @@ class CompilerInvocationBase { std::shared_ptr MigratorOpts; + /// Options controlling API notes. + std::shared_ptr APINotesOpts; + /// Options controlling IRgen and the backend. std::shared_ptr CodeGenOpts; @@ -131,6 +135,7 @@ class CompilerInvocationBase { const PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; } const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; } const MigratorOptions &getMigratorOpts() const { return *MigratorOpts; } + const APINotesOptions &getAPINotesOpts() const { return *APINotesOpts; } const CodeGenOptions &getCodeGenOpts() const { return *CodeGenOpts; } const FileSystemOptions &getFileSystemOpts() const { return *FSOpts; } const FrontendOptions &getFr
[clang] [APINotes] Upstream APINotesOptions (PR #70827)
egorzhdan wrote: Apologies for the broken build! I put up a re-land patch: https://github.com/llvm/llvm-project/pull/70975 https://github.com/llvm/llvm-project/pull/70827 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Revert "Revert "[APINotes] Upstream APINotesOptions"" (PR #70975)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/70975 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
egorzhdan wrote: @compnerd ping :) https://github.com/llvm/llvm-project/pull/73017 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Fix `-Wdocumentation` warning (NFC) (PR #73243)
https://github.com/egorzhdan created https://github.com/llvm/llvm-project/pull/73243 ``` llvm-project/clang/include/clang/AST/OpenMPClause.h:7762:14: warning: parameter 'Modifier' not found in the function declaration [-Wdocumentation] /// \param Modifier The modifier applied to 'order' clause. ^~~~ llvm-project/clang/include/clang/AST/OpenMPClause.h:7762:14: note: did you mean 'M'? /// \param Modifier The modifier applied to 'order' clause. ``` >From d1a1245492950601c8513c1a80b2d361b1ededc5 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Thu, 23 Nov 2023 14:19:17 + Subject: [PATCH] [Clang] Fix `-Wdocumentation` warning (NFC) ``` llvm-project/clang/include/clang/AST/OpenMPClause.h:7762:14: warning: parameter 'Modifier' not found in the function declaration [-Wdocumentation] /// \param Modifier The modifier applied to 'order' clause. ^~~~ llvm-project/clang/include/clang/AST/OpenMPClause.h:7762:14: note: did you mean 'M'? /// \param Modifier The modifier applied to 'order' clause. ``` --- clang/include/clang/AST/OpenMPClause.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 549f12e87df597a..51155e63dcb8f7d 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -7776,10 +7776,10 @@ class OMPOrderClause final : public OMPClause { /// \param MLoc Location of the modifier OMPOrderClause(OpenMPOrderClauseKind A, SourceLocation ALoc, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, OpenMPOrderClauseModifier M, + SourceLocation EndLoc, OpenMPOrderClauseModifier Modifier, SourceLocation MLoc) : OMPClause(llvm::omp::OMPC_order, StartLoc, EndLoc), -LParenLoc(LParenLoc), Kind(A), KindKwLoc(ALoc), Modifier(M), +LParenLoc(LParenLoc), Kind(A), KindKwLoc(ALoc), Modifier(Modifier), ModifierKwLoc(MLoc) {} /// Build an empty clause. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/73120 >From 5fcceda3e5904b82ccac23e2137d95e0e357b475 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 22 Nov 2023 13:54:04 + Subject: [PATCH] [APINotes] Upstream Driver and Frontend options that enable API Notes This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes --- clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Driver/Options.td | 12 clang/lib/Driver/ToolChains/Clang.cpp | 7 +++ clang/lib/Frontend/CompilerInstance.cpp | 8 clang/lib/Frontend/CompilerInvocation.cpp | 23 +++ 5 files changed, 51 insertions(+) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index cd77b22bf3ace4b..c3d5399905a3fda 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -405,6 +405,7 @@ LANGOPT(XLPragmaPack, 1, 0, "IBM XL #pragma pack handling") LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST") LANGOPT(APINotes, 1, 0, "use external API notes") +LANGOPT(APINotesModules, 1, 0, "use module-based external API notes") LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " "field padding (0: none, 1:least " diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b2f2bcb6ac37910..9191ccd2a66ac4a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1754,6 +1754,18 @@ def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, NormalizedValuesScope<"CodeGenOptions::SwiftAsyncFramePointerKind">, NormalizedValues<["Auto", "Always", "Never"]>, MarshallingInfoEnum, "Always">; +defm apinotes : BoolOption<"f", "apinotes", +LangOpts<"APINotes">, DefaultFalse, +PosFlag, +NegFlag, +BothFlags<[], [ClangOption, CC1Option], "external API notes support">>, +Group; +defm apinotes_modules : BoolOption<"f", "apinotes-modules", +LangOpts<"APINotesModules">, DefaultFalse, +PosFlag, +NegFlag, +BothFlags<[], [ClangOption, CC1Option], "module-based external API notes support">>, +Group; def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">, Group, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6dec117aed1056b..2d73f42772a29dc 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6720,6 +6720,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new); + if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false)) +CmdArgs.push_back("-fapinotes"); + if (Args.hasFlag(options::OPT_fapinotes_modules, + options::OPT_fno_apinotes_modules, false)) +CmdArgs.push_back("-fapinotes-modules"); + Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version); + // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, TC.IsBlocksDefault()) || diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index be5b38d6110fc3b..e5f8c0746a99dd4 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -756,6 +756,14 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind, TheSema->addExternalSource(ExternalSemaSrc.get()); ExternalSemaSrc->InitializeSema(*TheSema); } + + // If we're building a module and are supposed to load API notes, + // notify the API notes manager. + if (auto *currentModule = getPreprocessor().getCurrentModule()) { +(void)TheSema->APINotes.loadCurrentModuleAPINotes( +currentModule, getLangOpts().APINotesModules, +getAPINotesOpts().ModuleSearchPaths); + } } // Output Files diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 3f4ca02539080d0..3b92cc1281f9e0e 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3267,6 +3267,16 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, return Diags.getNumErrors() == NumErrorsBefore; } +static void GenerateAPINotesArgs(const APINotesOptions &Opts, + ArgumentConsumer Consumer) { + if (!Opts.SwiftVersion.empty()) +GenerateArg(Consumer, OPT_fapinotes_swift_version, +Opts.SwiftVersion.getAsString()); + + for (con
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
@@ -6720,6 +6720,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new); + if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false) || + Args.hasArg(options::OPT_iapinotes_modules)) { egorzhdan wrote: That's a good point, we don't actually need the outer check here. I removed it. https://github.com/llvm/llvm-project/pull/73120 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Driver and Frontend options that enable API Notes (PR #73120)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/73120 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Fix `-Wdocumentation` warning (NFC) (PR #73243)
https://github.com/egorzhdan closed https://github.com/llvm/llvm-project/pull/73243 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/73017 >From 4f7e29fe46a011153b3fbeee4d93875bb1a1a233 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 20 Nov 2023 18:03:18 + Subject: [PATCH 1/4] [APINotes] Upstream attributes that are created implicitly from APINotes --- clang/include/clang/Basic/Attr.td | 46 ++- clang/lib/Sema/SemaDeclAttr.cpp | 34 ++--- clang/lib/Serialization/ASTReaderDecl.cpp | 2 + clang/test/Sema/ns_error_enum.m | 3 +- clang/utils/TableGen/ClangAttrEmitter.cpp | 26 - 5 files changed, 93 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 03ed6accf700c4e..fb45991821ac059 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -301,6 +301,9 @@ class VariadicEnumArgument values, bit IsExternalType = isExternalType; } +// Represents an attribute wrapped by another attribute. +class AttrArgument : Argument; + // This handles one spelling of an attribute. class Spelling { string Name = name; @@ -2265,7 +2268,7 @@ def ObjCBridgeRelated : InheritableAttr { def NSErrorDomain : InheritableAttr { let Spellings = [GNU<"ns_error_domain">]; let Subjects = SubjectList<[Enum], ErrorDiag>; - let Args = [DeclArgument]; + let Args = [IdentifierArgument<"ErrorDomain">]; let Documentation = [NSErrorDomainDocs]; } @@ -2601,6 +2604,22 @@ def SwiftError : InheritableAttr { let Documentation = [SwiftErrorDocs]; } +def SwiftImportAsNonGeneric : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftImportPropertyAsAccessors : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + def SwiftName : InheritableAttr { let Spellings = [GNU<"swift_name">]; let Args = [StringArgument<"Name">]; @@ -2622,6 +2641,31 @@ def SwiftPrivate : InheritableAttr { let SimpleHandler = 1; } +def SwiftVersioned : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + +def SwiftVersionedRemoval : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes. + let Spellings = []; + let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, + BoolArgument<"IsReplacedByActive">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; + let AdditionalMembers = [{ +attr::Kind getAttrKindToRemove() const { + return static_cast(getRawKind()); +} + }]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 8966a301de1db3f..21835ca74dd69de 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6215,29 +6215,35 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } -static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *E = AL.getArgAsExpr(0); - auto Loc = E ? E->getBeginLoc() : AL.getLoc(); - - auto *DRE = dyn_cast(AL.getArgAsExpr(0)); - if (!DRE) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { +S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; return; } - auto *VD = dyn_cast(DRE->getDecl()); - if (!VD) { -S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + IdentifierLoc *IdentLoc = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!IdentLoc || !IdentLoc->Ident) { +// Try to locate the argument directly. +SourceLocation Loc = Attr.getLoc(); +if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) + Loc = Attr.getArgAsExpr(0)->getBeginLoc(); + +S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; return; } - if (!isNSStringType(VD->getType(), S.Context) && - !isCFStringType(VD->getType(), S.Context)) { -S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + // Verify that the identifier is a valid decl in the C decl namespace. + LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(), + Sema::LookupNameKind::LookupOrdinaryName); + if (!S.LookupName(Result, S.TUScope) || !Re
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
egorzhdan wrote: @compnerd ping ;) https://github.com/llvm/llvm-project/pull/73017 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #73017)
egorzhdan wrote: @compnerd pinging again :) https://github.com/llvm/llvm-project/pull/73017 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 5f2cf3a - [Clang][Preprocessor] Fix inconsistent `FLT_EVAL_METHOD` when compiling vs preprocessing
Author: Egor Zhdan Date: 2022-06-29T19:36:22+01:00 New Revision: 5f2cf3a21f3aabff85d178a110602ce150914ff7 URL: https://github.com/llvm/llvm-project/commit/5f2cf3a21f3aabff85d178a110602ce150914ff7 DIFF: https://github.com/llvm/llvm-project/commit/5f2cf3a21f3aabff85d178a110602ce150914ff7.diff LOG: [Clang][Preprocessor] Fix inconsistent `FLT_EVAL_METHOD` when compiling vs preprocessing When running `clang -E -Ofast` on macOS, the `__FLT_EVAL_METHOD__` macro is `0`, which causes the following typedef to be emitted into the preprocessed source: `typedef float float_t`. However, when running `clang -c -Ofast`, `__FLT_EVAL_METHOD__` is `-1`, and `typedef long double float_t` is emitted. This causes build errors for certain projects, which are not reproducible when compiling from preprocessed source. The issue is that `__FLT_EVAL_METHOD__` is configured in `Sema::Sema` which is not executed when running in `-E` mode. This change moves that logic into the preprocessor initialization method, which is invoked correctly in `-E` mode. rdar://96134605 rdar://92748429 Differential Revision: https://reviews.llvm.org/D128814 Added: Modified: clang/lib/Lex/Preprocessor.cpp clang/lib/Sema/Sema.cpp clang/test/Preprocessor/flt_eval_macro.cpp Removed: diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index fcc2d43a34ac9..281f01fb28a40 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -206,6 +206,18 @@ void Preprocessor::Initialize(const TargetInfo &Target, // Initialize the __FTL_EVAL_METHOD__ macro to the TargetInfo. setTUFPEvalMethod(getTargetInfo().getFPEvalMethod()); + + if (getLangOpts().getFPEvalMethod() == LangOptions::FEM_UnsetOnCommandLine) +// Use setting from TargetInfo. +setCurrentFPEvalMethod(SourceLocation(), Target.getFPEvalMethod()); + else +// Set initial value of __FLT_EVAL_METHOD__ from the command line. +setCurrentFPEvalMethod(SourceLocation(), getLangOpts().getFPEvalMethod()); + // When `-ffast-math` option is enabled, it triggers several driver math + // options to be enabled. Among those, only one the following two modes + // affect the eval-method: reciprocal or reassociate. + if (getLangOpts().AllowFPReassoc || getLangOpts().AllowRecip) +setCurrentFPEvalMethod(SourceLocation(), LangOptions::FEM_Indeterminable); } void Preprocessor::InitializeForModelFile() { diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index ad2cb62a18f0c..e2ec8eec60c33 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -249,21 +249,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, SemaPPCallbackHandler = Callbacks.get(); PP.addPPCallbacks(std::move(Callbacks)); SemaPPCallbackHandler->set(*this); - if (getLangOpts().getFPEvalMethod() == LangOptions::FEM_UnsetOnCommandLine) -// Use setting from TargetInfo. -PP.setCurrentFPEvalMethod(SourceLocation(), - ctxt.getTargetInfo().getFPEvalMethod()); - else -// Set initial value of __FLT_EVAL_METHOD__ from the command line. -PP.setCurrentFPEvalMethod(SourceLocation(), - getLangOpts().getFPEvalMethod()); + CurFPFeatures.setFPEvalMethod(PP.getCurrentFPEvalMethod()); - // When `-ffast-math` option is enabled, it triggers several driver math - // options to be enabled. Among those, only one the following two modes - // affect the eval-method: reciprocal or reassociate. - if (getLangOpts().AllowFPReassoc || getLangOpts().AllowRecip) -PP.setCurrentFPEvalMethod(SourceLocation(), - LangOptions::FEM_Indeterminable); } // Anchor Sema's type info to this TU. diff --git a/clang/test/Preprocessor/flt_eval_macro.cpp b/clang/test/Preprocessor/flt_eval_macro.cpp index 02829dcd267ec..37c28f21333f9 100644 --- a/clang/test/Preprocessor/flt_eval_macro.cpp +++ b/clang/test/Preprocessor/flt_eval_macro.cpp @@ -16,6 +16,9 @@ // RUN: %clang_cc1 -E -dM -triple=arm64_32-apple-ios -target-feature -sse \ // RUN: %s -o - | FileCheck %s -strict-whitespace +// RUN: %clang_cc1 -E -dM -triple=x86_64-apple-macos13.0 -ffast-math \ +// RUN: %s -o - | FileCheck %s -check-prefix=CHECK-MINUS-ONE -strict-whitespace + // RUN: %clang_cc1 -E -dM -triple i386-pc-windows -target-cpu pentium4 %s -o - \ // RUN: | FileCheck %s -strict-whitespace @@ -35,7 +38,9 @@ #define __GLIBC_FLT_EVAL_METHOD 2 #endif -#if __GLIBC_FLT_EVAL_METHOD == 0 || __GLIBC_FLT_EVAL_METHOD == 16 +#if __GLIBC_FLT_EVAL_METHOD == -1 +#define Name "MinusOne" +#elif __GLIBC_FLT_EVAL_METHOD == 0 || __GLIBC_FLT_EVAL_METHOD == 16 #define Name "One" #elif __GLIBC_FLT_EVAL_METHOD == 1 #define Name "Two" @@ -59,6 +64,7 @@ int foo() { // CHECK: #define Name "One" + // CHECK-MINUS-ONE: #define Name "MinusOne" // EXT: #define Na
[clang] 6ca2f19 - [Clang][Sema] Avoid crashing for `__builtin_memcpy_inline` with an array argument
Author: Egor Zhdan Date: 2022-03-14T12:47:30Z New Revision: 6ca2f1938f96a71abdecdd96508f48e4d20a5694 URL: https://github.com/llvm/llvm-project/commit/6ca2f1938f96a71abdecdd96508f48e4d20a5694 DIFF: https://github.com/llvm/llvm-project/commit/6ca2f1938f96a71abdecdd96508f48e4d20a5694.diff LOG: [Clang][Sema] Avoid crashing for `__builtin_memcpy_inline` with an array argument This change teaches the Sema logic for `__builtin_memcpy_inline` to implicitly convert arrays passed as arguments to pointers, similarly to regular `memcpy`. This code will no longer cause a compiler crash: ``` void f(char *p) { char s[1] = {0}; __builtin_memcpy_inline(p, s, 1); } ``` rdar://88147527 Differential Revision: https://reviews.llvm.org/D121475 Added: Modified: clang/lib/Sema/SemaChecking.cpp clang/test/Sema/builtins-memcpy-inline.cpp Removed: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2bd0d113fc992..2d14019cdbf18 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1943,6 +1943,17 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_nontemporal_store: return SemaBuiltinNontemporalOverloaded(TheCallResult); case Builtin::BI__builtin_memcpy_inline: { +auto ArgArrayConversionFailed = [&](unsigned Arg) { + ExprResult ArgExpr = + DefaultFunctionArrayLvalueConversion(TheCall->getArg(Arg)); + if (ArgExpr.isInvalid()) +return true; + TheCall->setArg(Arg, ArgExpr.get()); + return false; +}; + +if (ArgArrayConversionFailed(0) || ArgArrayConversionFailed(1)) + return true; clang::Expr *SizeOp = TheCall->getArg(2); // We warn about copying to or from `nullptr` pointers when `size` is // greater than 0. When `size` is value dependent we cannot evaluate its diff --git a/clang/test/Sema/builtins-memcpy-inline.cpp b/clang/test/Sema/builtins-memcpy-inline.cpp index 81b11fc021fff..30bc636c78393 100644 --- a/clang/test/Sema/builtins-memcpy-inline.cpp +++ b/clang/test/Sema/builtins-memcpy-inline.cpp @@ -36,3 +36,9 @@ void test_memcpy_inline_template(void *dst, const void *src) { // we do not try to evaluate size in non intantiated templates. __builtin_memcpy_inline(dst, src, size); } + +void test_memcpy_inline_implicit_conversion(void *ptr) { + char a[5]; + __builtin_memcpy_inline(ptr, a, 5); + __builtin_memcpy_inline(a, ptr, 5); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 33a9eac - [Clang] Support multiple attributes in a single pragma
Author: Egor Zhdan Date: 2022-03-18T12:20:41Z New Revision: 33a9eac6aaa495fce6fd9b17cd48aa57a95461e6 URL: https://github.com/llvm/llvm-project/commit/33a9eac6aaa495fce6fd9b17cd48aa57a95461e6 DIFF: https://github.com/llvm/llvm-project/commit/33a9eac6aaa495fce6fd9b17cd48aa57a95461e6.diff LOG: [Clang] Support multiple attributes in a single pragma This adds support for multiple attributes in `#pragma clang attribute push`, for example: ``` ``` or ``` ``` Related attributes can now be applied with a single pragma, which makes it harder for developers to make an accidental error later when editing the code. rdar://78269653 Differential Revision: https://reviews.llvm.org/D121283 Added: clang/test/AST/pragma-multiple-attributes-declspec.cpp clang/test/AST/pragma-multiple-attributes.cpp Modified: clang/docs/LanguageExtensions.rst clang/docs/ReleaseNotes.rst clang/include/clang/Basic/AttrSubjectMatchRules.h clang/include/clang/Basic/DiagnosticParseKinds.td clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/ParsePragma.cpp clang/test/FixIt/fixit-pragma-attribute.c clang/test/FixIt/fixit-pragma-attribute.cpp clang/test/Parser/pragma-attribute-declspec.cpp clang/test/Parser/pragma-attribute.cpp Removed: diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index d670bf55eec98..685f834a8495a 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -4121,8 +4121,22 @@ The ``__declspec`` style syntax is also supported: #pragma clang attribute pop -A single push directive accepts only one attribute regardless of the syntax -used. +A single push directive can contain multiple attributes, however, +only one syntax style can be used within a single directive: + +.. code-block:: c++ + + #pragma clang attribute push ([[noreturn, noinline]], apply_to = function) + + void function1(); // The function now has the [[noreturn]] and [[noinline]] attributes + + #pragma clang attribute pop + + #pragma clang attribute push (__attribute((noreturn, noinline)), apply_to = function) + + void function2(); // The function now has the __attribute((noreturn)) and __attribute((noinline)) attributes + + #pragma clang attribute pop Because multiple push directives can be nested, if you're writing a macro that expands to ``_Pragma("clang attribute")`` it's good hygiene (though not diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 21531bf72cd5b..5ddec067bc22f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -106,6 +106,8 @@ Attribute Changes in Clang - Statement attributes ``[[clang::noinline]]`` and ``[[clang::always_inline]]`` can be used to control inlining decisions at callsites. +- ``#pragma clang attribute push`` now supports multiple attributes within a single directive. + Windows Support --- diff --git a/clang/include/clang/Basic/AttrSubjectMatchRules.h b/clang/include/clang/Basic/AttrSubjectMatchRules.h index 4a4c1a883cf42..e3dcb943e59d4 100644 --- a/clang/include/clang/Basic/AttrSubjectMatchRules.h +++ b/clang/include/clang/Basic/AttrSubjectMatchRules.h @@ -18,6 +18,9 @@ namespace attr { /// A list of all the recognized kinds of attributes. enum SubjectMatchRule { #define ATTR_MATCH_RULE(X, Spelling, IsAbstract) X, +#include "clang/Basic/AttrSubMatchRulesList.inc" + SubjectMatchRule_Last = -1 +#define ATTR_MATCH_RULE(X, Spelling, IsAbstract) +1 #include "clang/Basic/AttrSubMatchRulesList.inc" }; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 7af15f5504ff9..1640a75391831 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1237,8 +1237,6 @@ def err_pragma_attribute_extra_tokens_after_attribute : Error< "extra tokens after attribute in a '#pragma clang attribute push'">; def err_pragma_attribute_unsupported_attribute : Error< "attribute %0 is not supported by '#pragma clang attribute'">; -def err_pragma_attribute_multiple_attributes : Error< - "more than one attribute specified in '#pragma clang attribute push'">; def err_pragma_attribute_expected_attribute_syntax : Error< "expected an attribute that is specified using the GNU, C++11 or '__declspec'" " syntax">; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 44a05eec4e350..135b2dfe54167 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -600,6 +600,8 @@ unsigned Parser::ParseClangAttributeArgs( bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs) { + unsigned ExistingAttrs = Attrs.size(); +
[clang] 1d0cc51 - [Clang][Driver] Fix include paths for `--sysroot /` on OpenBSD/FreeBSD
Author: Egor Zhdan Date: 2022-07-22T14:30:32+01:00 New Revision: 1d0cc510516d50c459f78896a0375fadb13a2b45 URL: https://github.com/llvm/llvm-project/commit/1d0cc510516d50c459f78896a0375fadb13a2b45 DIFF: https://github.com/llvm/llvm-project/commit/1d0cc510516d50c459f78896a0375fadb13a2b45.diff LOG: [Clang][Driver] Fix include paths for `--sysroot /` on OpenBSD/FreeBSD This is the same change as https://reviews.llvm.org/D126289, but applied for OpenBSD & FreeBSD. Differential Revision: https://reviews.llvm.org/D129654 Added: clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/bin/.keep clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/include/c++/v1/.keep clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/lib/.keep clang/test/Driver/Inputs/basic_openbsd_libcxx_tree/usr/bin/.keep clang/test/Driver/Inputs/basic_openbsd_libcxx_tree/usr/include/c++/v1/.keep clang/test/Driver/Inputs/basic_openbsd_libcxx_tree/usr/lib/.keep Modified: clang/lib/Driver/ToolChains/FreeBSD.cpp clang/lib/Driver/ToolChains/OpenBSD.cpp clang/test/Driver/freebsd.cpp clang/test/Driver/openbsd.cpp Removed: diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index fec80f85e2787..e5451c20a00c8 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -389,10 +389,10 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, // back to '/usr/lib' if it doesn't exist. if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() || Triple.isPPC32()) && - D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) -getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); + D.getVFS().exists(concat(getDriver().SysRoot, "/usr/lib32/crt1.o"))) +getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib32")); else -getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); +getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { @@ -411,14 +411,14 @@ unsigned FreeBSD::GetDefaultDwarfVersion() const { void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); + concat(getDriver().SysRoot, "/usr/include/c++/v1")); } void FreeBSD::addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/c++/4.2", "", "", - DriverArgs, CC1Args); + addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/c++/4.2"), + "", "", DriverArgs, CC1Args); } void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index 44cc9dee67f4d..8b3a40606ff32 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -284,7 +284,7 @@ SanitizerMask OpenBSD::getSupportedSanitizers() const { OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } void OpenBSD::AddClangSystemIncludeArgs( @@ -317,13 +317,14 @@ void OpenBSD::AddClangSystemIncludeArgs( return; } - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); } void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); + concat(getDriver().SysRoot, "/usr/include/c++/v1")); } void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, diff --git a/clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/bin/.keep b/clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/bin/.keep new file mode 100644 index 0..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/include/c++/v1/.keep b/clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/include/c++/v1/.keep new file mode 100644 index 0..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/lib/.keep b/clang/test/Driver/Inputs/basic_freebsd_libcxx_tree/usr/lib/.keep new file mode 100644 index 0
[clang] 2f04e70 - [Clang] Add DriverKit support
Author: Egor Zhdan Date: 2022-05-13T20:34:57+01:00 New Revision: 2f04e703bff3d9858f53225fa7c780b240c3e247 URL: https://github.com/llvm/llvm-project/commit/2f04e703bff3d9858f53225fa7c780b240c3e247 DIFF: https://github.com/llvm/llvm-project/commit/2f04e703bff3d9858f53225fa7c780b240c3e247.diff LOG: [Clang] Add DriverKit support This is the second patch that upstreams the support for Apple's DriverKit. The first patch: https://reviews.llvm.org/D118046. Differential Revision: https://reviews.llvm.org/D121911 Added: clang/test/CodeGen/availability-check-driverkit.c clang/test/Driver/Inputs/DriverKit19.0.sdk/SDKSettings.plist clang/test/Driver/Inputs/DriverKit19.0.sdk/System/DriverKit/usr/include/.keep clang/test/Driver/Inputs/basic_darwin_driverkit_sdk_usr_cxx_v1/System/DriverKit/usr/include/c++/v1/.keep clang/test/Driver/Inputs/basic_darwin_driverkit_sdk_usr_cxx_v1/System/DriverKit/usr/lib/.keep clang/test/Driver/Inputs/resource_dir/lib/darwin/libclang_rt.driverkit.a clang/test/Driver/darwin-ld-platform-version-driverkit.c clang/test/Driver/driverkit-arm64.c clang/test/Driver/driverkit-arm64e.c clang/test/Driver/driverkit-armv7k.s clang/test/Driver/driverkit-cplusplus.cpp clang/test/Driver/driverkit-exceptions.cpp clang/test/Driver/driverkit-framework.c clang/test/Driver/driverkit-rtti.cpp clang/test/Driver/driverkit-target-cpu.c clang/test/Driver/driverkit-version-min.c clang/test/Sema/attr-availability-driverkit.c Modified: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/Features.def clang/include/clang/Driver/Options.td clang/lib/Basic/LangStandards.cpp clang/lib/Basic/Targets/OSTargets.cpp clang/lib/Basic/Targets/OSTargets.h clang/lib/CodeGen/CGObjC.cpp clang/lib/Driver/Driver.cpp clang/lib/Driver/ToolChain.cpp clang/lib/Driver/ToolChains/Arch/ARM.cpp clang/lib/Driver/ToolChains/Arch/X86.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Driver/ToolChains/CommonArgs.cpp clang/lib/Driver/ToolChains/Darwin.cpp clang/lib/Driver/ToolChains/Darwin.h clang/test/Driver/darwin-ld.c clang/test/Driver/darwin-version.c clang/test/Driver/debug-options.c clang/test/Driver/incompatible_sysroot.c clang/test/Driver/instrprof-ld.c clang/test/Driver/pic.c clang/test/Driver/stack-protector.c clang/test/Frontend/darwin-version.c clang/test/Preprocessor/arm-target-features.c Removed: diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3c41edb474e89..0c95adfa237d7 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -870,6 +870,7 @@ def Availability : InheritableAttr { .Case("macos", "macOS") .Case("tvos", "tvOS") .Case("watchos", "watchOS") + .Case("driverkit", "DriverKit") .Case("ios_app_extension", "iOS (App Extension)") .Case("macos_app_extension", "macOS (App Extension)") .Case("tvos_app_extension", "tvOS (App Extension)") diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index b389ff9c02c45..d635da6b84b84 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1555,6 +1555,10 @@ attributes are ignored. Supported platforms are: ``watchos`` Apple's watchOS operating system. The minimum deployment target is specified by the ``-mwatchos-version-min=*version*`` command-line argument. + +``driverkit`` + Apple's DriverKit userspace kernel extensions. The minimum deployment target + is specified as part of the triple. A declaration can typically be used even when deploying back to a platform version prior to when the declaration was introduced. When this happens, the diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index c3f3fe79770db..f241d68a23ed9 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -61,6 +61,7 @@ FEATURE(attribute_availability_app_extension, true) FEATURE(attribute_availability_with_version_underscores, true) FEATURE(attribute_availability_tvos, true) FEATURE(attribute_availability_watchos, true) +FEATURE(attribute_availability_driverkit, true) FEATURE(attribute_availability_with_strict, true) FEATURE(attribute_availability_with_replacement, true) FEATURE(attribute_availability_in_templates, true) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index d1d7ca9698b14..ecdddff5b6831 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3914,6 +3914,7 @@ def nogpulib : Flag<["-"], "nogpulib">, MarshallingInfoFlag Flags<[CC1Option]>, Help
[clang] af845d7 - [Clang] Fix DriverKit tests on Linux
Author: Egor Zhdan Date: 2022-05-13T22:10:13+01:00 New Revision: af845d7e437a0380f65db841f2917f3c1a95ecf5 URL: https://github.com/llvm/llvm-project/commit/af845d7e437a0380f65db841f2917f3c1a95ecf5 DIFF: https://github.com/llvm/llvm-project/commit/af845d7e437a0380f65db841f2917f3c1a95ecf5.diff LOG: [Clang] Fix DriverKit tests on Linux Some new DriverKit tests were added in https://reviews.llvm.org/D121911, and unfortunately they fail on Linux build bots. Added: Modified: clang/test/Driver/darwin-ld-platform-version-driverkit.c clang/test/Driver/darwin-ld.c Removed: diff --git a/clang/test/Driver/darwin-ld-platform-version-driverkit.c b/clang/test/Driver/darwin-ld-platform-version-driverkit.c index f4fadc45079e..539d4c4f2557 100644 --- a/clang/test/Driver/darwin-ld-platform-version-driverkit.c +++ b/clang/test/Driver/darwin-ld-platform-version-driverkit.c @@ -6,11 +6,11 @@ // RUN: %clang -target x86_64-apple-driverkit19 -isysroot %t.sdk -mlinker-version=520 -### %t.o 2>&1 \ // RUN: | FileCheck --check-prefix=MISSING-SDK-JSON-WORKAROUND %s -// RUN: %clang -target arm64-apple-driverkit19 -isysroot %S/Inputs/MacOSX10.14.sdk -mlinker-version=520 -### %t.o 2>&1 \ +// RUN: %clang -target arm64-apple-driverkit19 -isysroot %S/Inputs/MacOSX10.14.sdk -fuse-ld= -mlinker-version=520 -### %t.o 2>&1 \ // RUN: | FileCheck --check-prefix=ARM64_NEW %s -// RUN: %clang -target arm64-apple-driverkit19 -isysroot %S/Inputs/MacOSX10.14.sdk -mlinker-version=400 -### %t.o 2>&1 \ +// RUN: %clang -target arm64-apple-driverkit19 -isysroot %S/Inputs/MacOSX10.14.sdk -fuse-ld= -mlinker-version=400 -### %t.o 2>&1 \ // RUN: | FileCheck --check-prefix=ARM64_OLD %s -// RUN: %clang -target arm64e-apple-driverkit19 -isysroot %S/Inputs/MacOSX10.14.sdk -mlinker-version=520 -### %t.o 2>&1 \ +// RUN: %clang -target arm64e-apple-driverkit19 -isysroot %S/Inputs/MacOSX10.14.sdk -fuse-ld= -mlinker-version=520 -### %t.o 2>&1 \ // RUN: | FileCheck --check-prefix=ARM64_NEW %s // CHECK: "-platform_version" "driverkit" "10.15.0" "10.14" diff --git a/clang/test/Driver/darwin-ld.c b/clang/test/Driver/darwin-ld.c index 73840d1b56b6..3a836d4dd1f1 100644 --- a/clang/test/Driver/darwin-ld.c +++ b/clang/test/Driver/darwin-ld.c @@ -185,7 +185,7 @@ // LINK_TVOS_KEXT: libclang_rt.cc_kext_tvos.a // LINK_TVOS_KEXT: libclang_rt.tvos.a -// RUN: %clang -target x86-64-apple-driverkit19.0 -mlinker-version=400 -resource-dir=%S/Inputs/resource_dir -### %t.o 2> %t.log +// RUN: %clang -target x86-64-apple-driverkit19.0 -fuse-ld= -mlinker-version=400 -resource-dir=%S/Inputs/resource_dir -### %t.o 2> %t.log // RUN: FileCheck -check-prefix=LINK_DRIVERKIT %s < %t.log // LINK_DRIVERKIT: {{ld(.exe)?"}} // LINK_DRIVERKIT: -driverkit_version_min ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream the remaining API Notes fixes and tests (PR #84773)
@@ -638,15 +638,15 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, PDecl->setInvalidDecl(); } - ProcessDeclAttributes(S, PDecl, FD.D); - // Regardless of setter/getter attribute, we save the default getter/setter // selector names in anticipation of declaration of setter/getter methods. PDecl->setGetterName(GetterSel, GetterNameLoc); PDecl->setSetterName(SetterSel, SetterNameLoc); PDecl->setPropertyAttributesAsWritten( makePropertyAttributesAsWritten(AttributesAsWritten)); + ProcessDeclAttributes(S, PDecl, FD.D); + if (Attributes & ObjCPropertyAttribute::kind_readonly) PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly); egorzhdan wrote: We have a test for this in this PR, `properties.m` – that's how I discovered this :) https://github.com/llvm/llvm-project/pull/84773 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream the remaining API Notes fixes and tests (PR #84773)
@@ -0,0 +1,4 @@ +Name: SomeBrokenLib +Functions: + - Name: do_something_with_pointers +Nu llabilityOfRet: O egorzhdan wrote: Alright, I added a comment https://github.com/llvm/llvm-project/pull/84773 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [APINotes] Upstream the remaining API Notes fixes and tests (PR #84773)
@@ -0,0 +1,44 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -Wno-private-module -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify + +// Test with Swift version 3.0. This should only affect the few APIs that have an entry in the 3.0 tables. egorzhdan wrote: Yes, in a sense that API Notes that apply attributes specific to Swift version 3.0 still exist in the SDK, and can be read by the compiler. https://github.com/llvm/llvm-project/pull/84773 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits