[clang] [InstallAPI] Verify that declarations in headers map to exports found in dylib (PR #85348)
Cyndy Ishida via cfe-commits
cfe-commits at lists.llvm.org
Sat Mar 16 13:06:23 PDT 2024
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/85348
>From d45081b0270f20a1313a35bd4ae12343e265ce7b Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ishida at apple.com>
Date: Wed, 13 Mar 2024 18:57:14 -0700
Subject: [PATCH 1/2] [InstallAPI] Verify that declarations in header map to
symbols found in dylib
* This patch completes support for verifying every declaration found in a
header is discovered in the dylib. Diagnostics are reported for each
class for differences that is representable in TBD files.
* This patch also now captures unavailable attributes that depend on target triples. This is needed for proper tbd file generation.
---
clang/include/clang/AST/Availability.h | 13 +-
.../clang/Basic/DiagnosticInstallAPIKinds.td | 23 +
.../include/clang/InstallAPI/DylibVerifier.h | 57 +-
clang/include/clang/InstallAPI/Frontend.h | 3 +
clang/include/clang/InstallAPI/MachO.h | 1 +
clang/lib/AST/Availability.cpp | 6 +-
clang/lib/InstallAPI/DylibVerifier.cpp | 326 ++++++++-
clang/lib/InstallAPI/Visitor.cpp | 2 +-
clang/test/InstallAPI/availability.test | 626 ++++++++++++++++++
clang/test/InstallAPI/diagnostics-cpp.test | 461 +++++++++++++
clang/test/InstallAPI/hiddens.test | 262 ++++++++
.../clang-installapi/ClangInstallAPI.cpp | 6 +-
clang/tools/clang-installapi/Options.cpp | 4 +-
13 files changed, 1766 insertions(+), 24 deletions(-)
create mode 100644 clang/test/InstallAPI/availability.test
create mode 100644 clang/test/InstallAPI/diagnostics-cpp.test
create mode 100644 clang/test/InstallAPI/hiddens.test
diff --git a/clang/include/clang/AST/Availability.h b/clang/include/clang/AST/Availability.h
index 5cfbaf0cdfbd21..2ccc607d4b63dc 100644
--- a/clang/include/clang/AST/Availability.h
+++ b/clang/include/clang/AST/Availability.h
@@ -67,6 +67,7 @@ struct AvailabilityInfo {
VersionTuple Introduced;
VersionTuple Deprecated;
VersionTuple Obsoleted;
+ bool Unavailable = false;
bool UnconditionallyDeprecated = false;
bool UnconditionallyUnavailable = false;
@@ -78,6 +79,9 @@ struct AvailabilityInfo {
/// Check if the symbol has been obsoleted.
bool isObsoleted() const { return !Obsoleted.empty(); }
+ /// Check if the symbol is unavailable for the active platform and os version.
+ bool isUnavailable() const { return Unavailable; }
+
/// Check if the symbol is unconditionally deprecated.
///
/// i.e. \code __attribute__((deprecated)) \endcode
@@ -91,9 +95,10 @@ struct AvailabilityInfo {
}
AvailabilityInfo(StringRef Domain, VersionTuple I, VersionTuple D,
- VersionTuple O, bool UD, bool UU)
+ VersionTuple O, bool U, bool UD, bool UU)
: Domain(Domain), Introduced(I), Deprecated(D), Obsoleted(O),
- UnconditionallyDeprecated(UD), UnconditionallyUnavailable(UU) {}
+ Unavailable(U), UnconditionallyDeprecated(UD),
+ UnconditionallyUnavailable(UU) {}
friend bool operator==(const AvailabilityInfo &Lhs,
const AvailabilityInfo &Rhs);
@@ -105,10 +110,10 @@ struct AvailabilityInfo {
inline bool operator==(const AvailabilityInfo &Lhs,
const AvailabilityInfo &Rhs) {
return std::tie(Lhs.Introduced, Lhs.Deprecated, Lhs.Obsoleted,
- Lhs.UnconditionallyDeprecated,
+ Lhs.Unavailable, Lhs.UnconditionallyDeprecated,
Lhs.UnconditionallyUnavailable) ==
std::tie(Rhs.Introduced, Rhs.Deprecated, Rhs.Obsoleted,
- Rhs.UnconditionallyDeprecated,
+ Rhs.Unavailable, Rhs.UnconditionallyDeprecated,
Rhs.UnconditionallyUnavailable);
}
diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
index 31be4f09cf3a1c..5ed2e23425dc5f 100644
--- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
+++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
@@ -17,4 +17,27 @@ def err_no_install_name : Error<"no install name specified: add -install_name <p
def err_no_output_file: Error<"no output file specified">;
} // end of command line category.
+let CategoryName = "Verification" in {
+def warn_target: Warning<"violations found for %0">;
+def err_library_missing_symbol : Error<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">;
+def warn_library_missing_symbol : Warning<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">;
+def err_library_hidden_symbol : Error<"declaration has external linkage, but symbol has internal linkage in dynamic library '%0'">;
+def warn_library_hidden_symbol : Warning<"declaration has external linkage, but symbol has internal linkage in dynamic library '%0'">;
+def warn_header_hidden_symbol : Warning<"symbol exported in dynamic library, but marked hidden in declaration '%0'">;
+def err_header_hidden_symbol : Error<"symbol exported in dynamic library, but marked hidden in declaration '%0'">;
+def err_header_symbol_missing : Error<"no declaration found for exported symbol '%0' in dynamic library">;
+def warn_header_availability_mismatch : Warning<"declaration '%0' is marked %select{available|unavailable}1,"
+ " but symbol is %select{not |}2exported in dynamic library">;
+def err_header_availability_mismatch : Error<"declaration '%0' is marked %select{available|unavailable}1,"
+ " but symbol is %select{not |}2exported in dynamic library">;
+def warn_dylib_symbol_flags_mismatch : Warning<"dynamic library symbol '%0' is "
+ "%select{weak defined|thread local}1, but its declaration is not">;
+def warn_header_symbol_flags_mismatch : Warning<"declaration '%0' is "
+ "%select{weak defined|thread local}1, but symbol is not in dynamic library">;
+def err_dylib_symbol_flags_mismatch : Error<"dynamic library symbol '%0' is "
+ "%select{weak defined|thread local}1, but its declaration is not">;
+def err_header_symbol_flags_mismatch : Error<"declaration '%0' is "
+ "%select{weak defined|thread local}1, but symbol is not in dynamic library">;
+} // end of Verification category.
+
} // end of InstallAPI component
diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h
index 72c4743fdf65e0..2094548ced8d5f 100644
--- a/clang/include/clang/InstallAPI/DylibVerifier.h
+++ b/clang/include/clang/InstallAPI/DylibVerifier.h
@@ -38,19 +38,34 @@ class DylibVerifier {
// Current target being verified against the AST.
llvm::MachO::Target Target;
+ // Target specific API from binary.
+ RecordsSlice *DylibSlice;
+
// Query state of verification after AST has been traversed.
Result FrontendState;
// First error for AST traversal, which is tied to the target triple.
bool DiscoveredFirstError;
+
+ // Determines what kind of banner to print a violation for.
+ bool PrintArch = false;
+
+ // Engine for reporting violations.
+ DiagnosticsEngine *Diag = nullptr;
+
+ // Handle diagnostics reporting for target level violations.
+ void emitDiag(llvm::function_ref<void()> Report);
+
+ VerifierContext() = default;
+ VerifierContext(DiagnosticsEngine *Diag) : Diag(Diag) {}
};
DylibVerifier() = default;
DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag,
VerificationMode Mode, bool Demangle)
- : Dylib(std::move(Dylib)), Diag(Diag), Mode(Mode), Demangle(Demangle),
- Exports(std::make_unique<SymbolSet>()) {}
+ : Dylib(std::move(Dylib)), Mode(Mode), Demangle(Demangle),
+ Exports(std::make_unique<SymbolSet>()), Ctx(VerifierContext{Diag}) {}
Result verify(GlobalRecord *R, const FrontendAttrs *FA);
Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA);
@@ -66,6 +81,13 @@ class DylibVerifier {
/// Get result of verification.
Result getState() const { return Ctx.FrontendState; }
+ /// Set different source managers to the same diagnostics engine.
+ void setSourceManager(SourceManager &SourceMgr) const {
+ if (!Ctx.Diag)
+ return;
+ Ctx.Diag->setSourceManager(&SourceMgr);
+ }
+
private:
/// Determine whether to compare declaration to symbol in binary.
bool canVerify();
@@ -73,6 +95,29 @@ class DylibVerifier {
/// Shared implementation for verifying exported symbols.
Result verifyImpl(Record *R, SymbolContext &SymCtx);
+ /// Check if declaration is marked as obsolete, they are
+ // expected to result in a symbol mismatch.
+ bool shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
+ const Record *DR);
+
+ /// Compare the visibility declarations to the linkage of symbol found in
+ /// dylib.
+ Result compareVisibility(const Record *R, SymbolContext &SymCtx,
+ const Record *DR);
+
+ /// An ObjCInterfaceRecord can represent up to three symbols. When verifying,
+ // account for this granularity.
+ bool compareObjCInterfaceSymbols(const Record *R, SymbolContext &SymCtx,
+ const ObjCInterfaceRecord *DR);
+
+ /// Validate availability annotations against dylib.
+ Result compareAvailability(const Record *R, SymbolContext &SymCtx,
+ const Record *DR);
+
+ /// Compare and validate matching symbol flags.
+ bool compareSymbolFlags(const Record *R, SymbolContext &SymCtx,
+ const Record *DR);
+
/// Update result state on each call to `verify`.
void updateState(Result State);
@@ -80,14 +125,14 @@ class DylibVerifier {
void addSymbol(const Record *R, SymbolContext &SymCtx,
TargetList &&Targets = {});
+ /// Find matching dylib slice for target triple that is being parsed.
+ void assignSlice(const Target &T);
+
// Symbols in dylib.
llvm::MachO::Records Dylib;
- // Engine for reporting violations.
- [[maybe_unused]] DiagnosticsEngine *Diag = nullptr;
-
// Controls what class of violations to report.
- [[maybe_unused]] VerificationMode Mode = VerificationMode::Invalid;
+ VerificationMode Mode = VerificationMode::Invalid;
// Attempt to demangle when reporting violations.
bool Demangle = false;
diff --git a/clang/include/clang/InstallAPI/Frontend.h b/clang/include/clang/InstallAPI/Frontend.h
index 660fc8cd69a59d..5cccd891c58093 100644
--- a/clang/include/clang/InstallAPI/Frontend.h
+++ b/clang/include/clang/InstallAPI/Frontend.h
@@ -17,6 +17,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/InstallAPI/Context.h"
+#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/Visitor.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -34,6 +35,8 @@ class InstallAPIAction : public ASTFrontendAction {
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override {
+ Ctx.Diags->getClient()->BeginSourceFile(CI.getLangOpts());
+ Ctx.Verifier->setSourceManager(CI.getSourceManager());
return std::make_unique<InstallAPIVisitor>(
CI.getASTContext(), Ctx, CI.getSourceManager(), CI.getPreprocessor());
}
diff --git a/clang/include/clang/InstallAPI/MachO.h b/clang/include/clang/InstallAPI/MachO.h
index 6dee6f22420381..a77766511fa3e5 100644
--- a/clang/include/clang/InstallAPI/MachO.h
+++ b/clang/include/clang/InstallAPI/MachO.h
@@ -32,6 +32,7 @@ using ObjCInterfaceRecord = llvm::MachO::ObjCInterfaceRecord;
using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord;
using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord;
using Records = llvm::MachO::Records;
+using RecordsSlice = llvm::MachO::RecordsSlice;
using BinaryAttrs = llvm::MachO::RecordsSlice::BinaryAttrs;
using SymbolSet = llvm::MachO::SymbolSet;
using SimpleSymbol = llvm::MachO::SimpleSymbol;
diff --git a/clang/lib/AST/Availability.cpp b/clang/lib/AST/Availability.cpp
index d0054e37e4dcd2..238359a2dedfcf 100644
--- a/clang/lib/AST/Availability.cpp
+++ b/clang/lib/AST/Availability.cpp
@@ -28,9 +28,9 @@ AvailabilityInfo AvailabilityInfo::createFromDecl(const Decl *Decl) {
for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
if (A->getPlatform()->getName() != PlatformName)
continue;
- Availability =
- AvailabilityInfo(A->getPlatform()->getName(), A->getIntroduced(),
- A->getDeprecated(), A->getObsoleted(), false, false);
+ Availability = AvailabilityInfo(
+ A->getPlatform()->getName(), A->getIntroduced(), A->getDeprecated(),
+ A->getObsoleted(), A->getUnavailable(), false, false);
break;
}
diff --git a/clang/lib/InstallAPI/DylibVerifier.cpp b/clang/lib/InstallAPI/DylibVerifier.cpp
index b7dd85d63fa14f..700763b3fee0db 100644
--- a/clang/lib/InstallAPI/DylibVerifier.cpp
+++ b/clang/lib/InstallAPI/DylibVerifier.cpp
@@ -1,5 +1,6 @@
#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/FrontendRecords.h"
+#include "clang/InstallAPI/InstallAPIDiagnostic.h"
#include "llvm/Demangle/Demangle.h"
using namespace llvm::MachO;
@@ -24,6 +25,9 @@ struct DylibVerifier::SymbolContext {
// The ObjCInterface symbol type, if applicable.
ObjCIFSymbolKind ObjCIFKind = ObjCIFSymbolKind::None;
+
+ // Whether Decl is inlined.
+ bool Inlined = false;
};
static std::string
@@ -80,10 +84,11 @@ getAnnotatedName(const Record *R, EncodeKind Kind, StringRef Name,
}
static std::string demangle(StringRef Name) {
- // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
- if (!(Name.starts_with("_Z") || Name.starts_with("___Z")))
+ // InstallAPI currently only supports itanium manglings.
+ if (!(Name.starts_with("_Z") || Name.starts_with("__Z") ||
+ Name.starts_with("___Z")))
return Name.str();
- char *Result = llvm::itaniumDemangle(Name.data());
+ char *Result = llvm::itaniumDemangle(Name);
if (!Result)
return Name.str();
@@ -109,6 +114,30 @@ static DylibVerifier::Result updateResult(const DylibVerifier::Result Prev,
return Curr;
}
+// __private_extern__ is a deprecated specifier that clang does not
+// respect in all contexts, it should just be considered hidden for InstallAPI.
+static bool shouldIgnorePrivateExternAttr(const Decl *D) {
+ if (const FunctionDecl *FD = cast<FunctionDecl>(D))
+ return FD->getStorageClass() == StorageClass::SC_PrivateExtern;
+ if (const VarDecl *VD = cast<VarDecl>(D))
+ return VD->getStorageClass() == StorageClass::SC_PrivateExtern;
+
+ return false;
+}
+
+Record *findRecordFromSlice(const RecordsSlice *Slice, StringRef Name,
+ EncodeKind Kind) {
+ switch (Kind) {
+ case EncodeKind::GlobalSymbol:
+ return Slice->findGlobal(Name);
+ case EncodeKind::ObjectiveCInstanceVariable:
+ return Slice->findObjCIVar(Name.contains('.'), Name);
+ case EncodeKind::ObjectiveCClass:
+ case EncodeKind::ObjectiveCClassEHType:
+ return Slice->findObjCInterface(Name);
+ }
+ llvm_unreachable("unexpected end when finding record");
+}
void DylibVerifier::updateState(Result State) {
Ctx.FrontendState = updateResult(Ctx.FrontendState, State);
@@ -122,17 +151,272 @@ void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx,
Exports->addGlobal(SymCtx.Kind, SymCtx.SymbolName, R->getFlags(), Targets);
}
+bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
+ const Record *DR) {
+ return SymCtx.FA->Avail.isObsoleted();
+}
+
+bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R,
+ SymbolContext &SymCtx,
+ const ObjCInterfaceRecord *DR) {
+ const bool IsDeclVersionComplete =
+ ((SymCtx.ObjCIFKind & ObjCIFSymbolKind::Class) ==
+ ObjCIFSymbolKind::Class) &&
+ ((SymCtx.ObjCIFKind & ObjCIFSymbolKind::MetaClass) ==
+ ObjCIFSymbolKind::MetaClass);
+
+ const bool IsDylibVersionComplete = DR->isCompleteInterface();
+
+ // The common case, a complete ObjCInterface.
+ if (IsDeclVersionComplete && IsDylibVersionComplete)
+ return true;
+
+ auto PrintDiagnostic = [&](auto SymLinkage, const Record *Record,
+ StringRef SymName, bool PrintAsWarning = false) {
+ if (SymLinkage == RecordLinkage::Unknown)
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ PrintAsWarning ? diag::warn_library_missing_symbol
+ : diag::err_library_missing_symbol)
+ << SymName;
+ });
+ else
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ PrintAsWarning ? diag::warn_library_hidden_symbol
+ : diag::err_library_hidden_symbol)
+ << SymName;
+ });
+ };
+
+ if (IsDeclVersionComplete) {
+ // The decl represents a complete ObjCInterface, but the symbols in the
+ // dylib do not. Determine which symbol is missing. To keep older projects
+ // building, treat this as a warning.
+ if (!DR->isExportedSymbol(ObjCIFSymbolKind::Class))
+ PrintDiagnostic(DR->getLinkageForSymbol(ObjCIFSymbolKind::Class), R,
+ getAnnotatedName(R, SymCtx.Kind, SymCtx.PrettyPrintName,
+ /*ValidSourceLoc=*/true,
+ ObjCIFSymbolKind::Class),
+ /*PrintAsWarning=*/true);
+
+ if (!DR->isExportedSymbol(ObjCIFSymbolKind::MetaClass))
+ PrintDiagnostic(DR->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass), R,
+ getAnnotatedName(R, SymCtx.Kind, SymCtx.PrettyPrintName,
+ /*ValidSourceLoc=*/true,
+ ObjCIFSymbolKind::MetaClass),
+ /*PrintAsWarning=*/true);
+ return true;
+ }
+
+ if (DR->isExportedSymbol(SymCtx.ObjCIFKind)) {
+ if (!IsDylibVersionComplete) {
+ // Both the declaration and dylib have a non-complete interface.
+ SymCtx.Kind = EncodeKind::GlobalSymbol;
+ SymCtx.SymbolName = R->getName();
+ }
+ return true;
+ }
+
+ // At this point that means there was not a matching class symbol
+ // to represent the one discovered as a declaration.
+ PrintDiagnostic(DR->getLinkageForSymbol(SymCtx.ObjCIFKind), R,
+ SymCtx.PrettyPrintName);
+ return false;
+}
+
+DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R,
+ SymbolContext &SymCtx,
+ const Record *DR) {
+
+ if (R->isExported()) {
+ if (!DR) {
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ diag::err_library_missing_symbol)
+ << SymCtx.PrettyPrintName;
+ });
+ return Result::Invalid;
+ }
+ if (DR->isInternal()) {
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ diag::err_library_hidden_symbol)
+ << SymCtx.PrettyPrintName;
+ });
+ return Result::Invalid;
+ }
+ }
+
+ // Emit a diagnostic for hidden declarations with external symbols, except
+ // when theres an inlined attribute.
+ if ((R->isInternal() && !SymCtx.Inlined) && DR && DR->isExported()) {
+
+ if (Mode == VerificationMode::ErrorsOnly)
+ return Result::Ignore;
+
+ if (shouldIgnorePrivateExternAttr(SymCtx.FA->D))
+ return Result::Ignore;
+
+ unsigned ID;
+ Result Outcome;
+ if (Mode == VerificationMode::ErrorsAndWarnings) {
+ ID = diag::warn_header_hidden_symbol;
+ Outcome = Result::Ignore;
+ } else {
+ ID = diag::err_header_hidden_symbol;
+ Outcome = Result::Invalid;
+ }
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(), ID)
+ << SymCtx.PrettyPrintName;
+ });
+ return Outcome;
+ }
+
+ if (R->isInternal())
+ return Result::Ignore;
+
+ return Result::Valid;
+}
+
+DylibVerifier::Result DylibVerifier::compareAvailability(const Record *R,
+ SymbolContext &SymCtx,
+ const Record *DR) {
+ if (!SymCtx.FA->Avail.isUnavailable())
+ return Result::Valid;
+
+ const bool IsDeclAvailable = SymCtx.FA->Avail.isUnavailable();
+
+ switch (Mode) {
+ case VerificationMode::ErrorsAndWarnings:
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ diag::warn_header_availability_mismatch)
+ << SymCtx.PrettyPrintName << IsDeclAvailable << IsDeclAvailable;
+ });
+ return Result::Ignore;
+ case VerificationMode::Pedantic:
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ diag::err_header_availability_mismatch)
+ << SymCtx.PrettyPrintName << IsDeclAvailable << IsDeclAvailable;
+ });
+ return Result::Invalid;
+ case VerificationMode::ErrorsOnly:
+ return Result::Ignore;
+ case VerificationMode::Invalid:
+ llvm_unreachable("Unexpected verification mode symbol verification");
+ }
+ llvm_unreachable("Unexpected verification mode symbol verification");
+}
+
+bool DylibVerifier::compareSymbolFlags(const Record *R, SymbolContext &SymCtx,
+ const Record *DR) {
+ std::string DisplayName =
+ Demangle ? demangle(DR->getName()) : DR->getName().str();
+
+ if (DR->isThreadLocalValue() && !R->isThreadLocalValue()) {
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ diag::err_dylib_symbol_flags_mismatch)
+ << getAnnotatedName(DR, SymCtx.Kind, DisplayName)
+ << DR->isThreadLocalValue();
+ });
+ return false;
+ }
+ if (!DR->isThreadLocalValue() && R->isThreadLocalValue()) {
+ Ctx.emitDiag([&]() {
+ SymCtx.FA->D->getLocation(),
+ Ctx.Diag->Report(diag::err_header_symbol_flags_mismatch)
+ << SymCtx.PrettyPrintName << R->isThreadLocalValue();
+ });
+ return false;
+ }
+
+ if (DR->isWeakDefined() && !R->isWeakDefined()) {
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ diag::err_dylib_symbol_flags_mismatch)
+ << getAnnotatedName(DR, SymCtx.Kind, DisplayName)
+ << R->isWeakDefined();
+ });
+ return false;
+ }
+ if (!DR->isWeakDefined() && R->isWeakDefined()) {
+ Ctx.emitDiag([&]() {
+ Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
+ diag::err_header_symbol_flags_mismatch)
+ << SymCtx.PrettyPrintName << R->isWeakDefined();
+ });
+ return false;
+ }
+
+ return true;
+}
+
DylibVerifier::Result DylibVerifier::verifyImpl(Record *R,
SymbolContext &SymCtx) {
R->setVerify();
if (!canVerify()) {
// Accumulate symbols when not in verifying against dylib.
- if (R->isExported() && !SymCtx.FA->Avail.isUnconditionallyUnavailable() &&
+ if (R->isExported() && !SymCtx.FA->Avail.isUnavailable() &&
!SymCtx.FA->Avail.isObsoleted()) {
addSymbol(R, SymCtx);
}
return Ctx.FrontendState;
}
+
+ Record *DR =
+ findRecordFromSlice(Ctx.DylibSlice, SymCtx.SymbolName, SymCtx.Kind);
+ if (DR)
+ DR->setVerify();
+
+ if (shouldIgnoreObsolete(R, SymCtx, DR)) {
+ updateState(Result::Ignore);
+ return Ctx.FrontendState;
+ }
+
+ // Unavailable declarations don't need matching symbols.
+ if (SymCtx.FA->Avail.isUnavailable() && (!DR || DR->isInternal())) {
+ updateState(Result::Valid);
+ return Ctx.FrontendState;
+ }
+
+ Result VisibilityCheck = compareVisibility(R, SymCtx, DR);
+ if (VisibilityCheck != Result::Valid) {
+ updateState(VisibilityCheck);
+ return Ctx.FrontendState;
+ }
+
+ // All missing symbol cases to diagnose have been handled now.
+ if (!DR) {
+ updateState(Result::Ignore);
+ return Ctx.FrontendState;
+ }
+
+ // Check for mismatching ObjC interfaces.
+ if (SymCtx.ObjCIFKind != ObjCIFSymbolKind::None) {
+ if (!compareObjCInterfaceSymbols(
+ R, SymCtx, Ctx.DylibSlice->findObjCInterface(DR->getName()))) {
+ updateState(Result::Invalid);
+ return Ctx.FrontendState;
+ }
+ }
+
+ Result AvailabilityCheck = compareAvailability(R, SymCtx, DR);
+ if (AvailabilityCheck != Result::Valid) {
+ updateState(AvailabilityCheck);
+ return Ctx.FrontendState;
+ }
+
+ if (!compareSymbolFlags(R, SymCtx, DR)) {
+ updateState(Result::Invalid);
+ return Ctx.FrontendState;
+ }
+
+ addSymbol(R, SymCtx);
+ updateState(Result::Valid);
return Ctx.FrontendState;
}
@@ -140,10 +424,29 @@ bool DylibVerifier::canVerify() {
return Ctx.FrontendState != Result::NoVerify;
}
+void DylibVerifier::assignSlice(const Target &T) {
+ assert(T == Ctx.Target && "Active targets should match.");
+ if (Dylib.empty())
+ return;
+
+ // Note: there are no reexport slices with binaries, as opposed to TBD files,
+ // so it can be assumed that the target match is the active top-level library.
+ auto It = find_if(
+ Dylib, [&T](const auto &Slice) { return T == Slice->getTarget(); });
+
+ assert(It != Dylib.end() && "Target slice should always exist.");
+ Ctx.DylibSlice = It->get();
+}
+
void DylibVerifier::setTarget(const Target &T) {
Ctx.Target = T;
Ctx.DiscoveredFirstError = false;
- updateState(Dylib.empty() ? Result::NoVerify : Result::Ignore);
+ if (Dylib.empty()) {
+ updateState(Result::NoVerify);
+ return;
+ }
+ updateState(Result::Ignore);
+ assignSlice(T);
}
DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R,
@@ -205,8 +508,21 @@ DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R,
getAnnotatedName(R, Sym.Kind, Demangle ? demangle(Sym.Name) : Sym.Name);
SymCtx.Kind = Sym.Kind;
SymCtx.FA = FA;
+ SymCtx.Inlined = R->isInlined();
return verifyImpl(R, SymCtx);
}
+void DylibVerifier::VerifierContext::emitDiag(
+ llvm::function_ref<void()> Report) {
+ if (!DiscoveredFirstError) {
+ Diag->Report(diag::warn_target)
+ << (PrintArch ? getArchitectureName(Target.Arch)
+ : getTargetTripleName(Target));
+ DiscoveredFirstError = true;
+ }
+
+ Report();
+}
+
} // namespace installapi
} // namespace clang
diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp
index 187afe59309d37..452c8f2fb1e489 100644
--- a/clang/lib/InstallAPI/Visitor.cpp
+++ b/clang/lib/InstallAPI/Visitor.cpp
@@ -681,7 +681,7 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
std::string Name = getMangledName(M);
auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Function, Avail, D,
+ GlobalRecord::Kind::Function, Avail, M,
*Access, getFlags(WeakDef));
Ctx.Verifier->verify(GR, FA);
}
diff --git a/clang/test/InstallAPI/availability.test b/clang/test/InstallAPI/availability.test
new file mode 100644
index 00000000000000..5e8f7c6e509eb4
--- /dev/null
+++ b/clang/test/InstallAPI/availability.test
@@ -0,0 +1,626 @@
+; RUN: rm -rf %t
+; RUN: split-file %s %t
+; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json
+
+; RUN: yaml2obj %t/Availability.yaml -o %t/System/Library/Frameworks/Availability.framework/Availability
+
+; RUN: clang-installapi \
+; RUN: --target=x86_64-apple-macos13 \
+; RUN: -install_name /System/Library/Frameworks/Availability.framework/Versions/A/Availability \
+; RUN: -current_version 1 -compatibility_version 1 \
+; RUN: -F %t/System/Library/Frameworks \
+; RUN: %t/inputs.json -o output.tbd \
+; RUN: --verify-against=%t/System/Library/Frameworks/Availability.framework/Availability \
+; RUN: --verify-mode=ErrorsOnly --filetype=tbd-v5 2>&1 | FileCheck -allow-empty -check-prefix=ERRORSONLY %s
+
+; RUN: clang-installapi \
+; RUN: --target=x86_64-apple-macos13 \
+; RUN: -install_name /System/Library/Frameworks/Availability.framework/Versions/A/Availability \
+; RUN: -current_version 1 -compatibility_version 1 \
+; RUN: -F %t/System/Library/Frameworks \
+; RUN: %t/inputs.json -o output-warnings.tbd \
+; RUN: --verify-against=%t/System/Library/Frameworks/Availability.framework/Availability \
+; RUN: --verify-mode=ErrorsAndWarnings 2>&1 | FileCheck -check-prefixes=VIOLATIONS,ERRORSANDWARNINGS %s
+
+; RUN: not clang-installapi \
+; RUN: --target=x86_64-apple-macos13 \
+; RUN: -install_name /System/Library/Frameworks/Availability.framework/Versions/A/Availability \
+; RUN: -current_version 1 -compatibility_version 1 \
+; RUN: -F %t/System/Library/Frameworks \
+; RUN: %t/inputs.json -o output-pedantic.tbd \
+; RUN: --verify-against=%t/System/Library/Frameworks/Availability.framework/Availability \
+; RUN: --verify-mode=Pedantic 2>&1 | FileCheck -check-prefixes=VIOLATIONS,PEDANTIC %s
+
+; ERRORSONLY-NOT: error
+; ERRORSONLY-NOT: warning
+
+; ERRORSANDWARNINGS-NOT: error
+; VIOLATIONS: warning: violations found for x86_64-apple-macos
+; VIOLATIONS: declaration 'publicGlobalVariable' is marked unavailable, but symbol is exported in dynamic library
+; VIOLATIONS-NEXT: extern int publicGlobalVariable NS_AVAILABLE
+; VIOLATIONS: declaration 'Foo' is marked unavailable, but symbol is exported in dynamic library
+; VIOLATIONS-NEXT: @interface Foo : NSObject
+; VIOLATIONS: declaration 'privateGlobalVariable' is marked unavailable, but symbol is exported in dynamic library
+; VIOLATIONS-NEXT: extern int privateGlobalVariable;
+
+; ERRORSANDWARNINGS-NOT: warning
+; PEDANTIC-NOT: error
+
+;--- inputs.json.in
+{
+ "headers": [ {
+ "path" : "DSTROOT/System/Library/Frameworks/Availability.framework/Headers/Availability.h",
+ "type" : "public"
+ },
+ {
+ "path" : "DSTROOT/System/Library/Frameworks/Availability.framework/PrivateHeaders/AvailabilityPrivate.h",
+ "type" : "private"
+ }
+ ],
+ "version": "3"
+}
+
+;--- System/Library/Frameworks/Availability.framework/Headers/AV_Defines.h
+#ifndef AV_DEFINES
+#define AV_DEFINES
+
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=NA)))
+
+ at interface NSObject
+ at end
+
+#endif //AV_DEFINES
+
+;--- System/Library/Frameworks/Availability.framework/PrivateHeaders/AvailabilityPrivate.h
+#import <Availability/AV_Defines.h>
+// Test private global variable.
+NS_AVAILABLE
+extern int privateGlobalVariable;
+
+;--- System/Library/Frameworks/Availability.framework/Headers/Availability.h
+#import <Availability/AV_Defines.h>
+extern int publicGlobalVariable NS_AVAILABLE;
+
+// Test public ObjC class
+NS_AVAILABLE
+ at interface Foo : NSObject
+ at end
+
+// Test unavailable attribute.
+#ifdef __i386__
+#define UNAVAILABLE_I386 __attribute__((unavailable))
+#else
+#define UNAVAILABLE_I386
+#endif
+extern int publicGlobalVariable2 UNAVAILABLE_I386;
+
+extern int publicGlobalVariable3 __attribute__((unavailable))
+__attribute__((availability(macosx, introduced = 10.9)));
+
+// Test obsoleted with exported variable.
+extern int publicGlobalVariable4 __attribute__((availability(
+ macosx, introduced = 10.9, deprecated = 10.10, obsoleted = 10.11)));
+// Test obsoleted with non-existent variable.
+extern int publicGlobalVariable5 __attribute__((availability(
+ macosx, introduced = 10.9, deprecated = 10.10, obsoleted = 10.11)));
+
+#ifdef __i386__
+#define OBSOLETE_I386 __attribute__((availability(macosx, obsoleted = 10.11)))
+#else
+#define OBSOLETE_I386
+#endif
+extern int publicGlobalVariable6 OBSOLETE_I386;
+
+
+/// Created from:
+// int publicGlobalVariable; int privateGlobalVariable;
+//
+// @implementation Foo
+// @end
+//
+// #ifndef __i386__
+// int publicGlobalVariable2;
+// #endif
+//
+// int publicGlobalVariable3;
+// int publicGlobalVariable4;
+//
+// #ifndef __i386__
+// int publicGlobalVariable6;
+// #endif
+;--- Availability.yaml
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x1000007
+ cpusubtype: 0x3
+ filetype: 0x6
+ ncmds: 14
+ sizeofcmds: 1312
+ flags: 0x100085
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: __TEXT
+ vmaddr: 0
+ vmsize: 8192
+ fileoff: 0
+ filesize: 8192
+ maxprot: 5
+ initprot: 5
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0x1140
+ size: 0
+ offset: 0x1140
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000000
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: ''
+ - sectname: __cstring
+ segname: __TEXT
+ addr: 0x1140
+ size: 4
+ offset: 0x1140
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x2
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 466F6F00
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: __DATA_CONST
+ vmaddr: 8192
+ vmsize: 4096
+ fileoff: 8192
+ filesize: 4096
+ maxprot: 3
+ initprot: 3
+ nsects: 2
+ flags: 16
+ Sections:
+ - sectname: __objc_classlist
+ segname: __DATA_CONST
+ addr: 0x2000
+ size: 8
+ offset: 0x2000
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x10000000
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: B830000000000000
+ - sectname: __objc_imageinfo
+ segname: __DATA_CONST
+ addr: 0x2008
+ size: 8
+ offset: 0x2008
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '0000000040000000'
+ - cmd: LC_SEGMENT_64
+ cmdsize: 312
+ segname: __DATA
+ vmaddr: 12288
+ vmsize: 4096
+ fileoff: 12288
+ filesize: 4096
+ maxprot: 3
+ initprot: 3
+ nsects: 3
+ flags: 0
+ Sections:
+ - sectname: __objc_const
+ segname: __DATA
+ addr: 0x3000
+ size: 144
+ offset: 0x3000
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '010000002800000028000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ - sectname: __objc_data
+ segname: __DATA
+ addr: 0x3090
+ size: 80
+ offset: 0x3090
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '0000000000000000000000000000000000000000000000000000000000000000003000000000000090300000000000000000000000000000000000000000000000000000000000004830000000000000'
+ - sectname: __common
+ segname: __DATA
+ addr: 0x30E0
+ size: 24
+ offset: 0x0
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x1
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __LINKEDIT
+ vmaddr: 16384
+ vmsize: 824
+ fileoff: 16384
+ filesize: 824
+ maxprot: 1
+ initprot: 1
+ nsects: 0
+ flags: 0
+ - cmd: LC_DYLD_INFO_ONLY
+ cmdsize: 48
+ rebase_off: 16384
+ rebase_size: 16
+ bind_off: 16400
+ bind_size: 104
+ weak_bind_off: 0
+ weak_bind_size: 0
+ lazy_bind_off: 0
+ lazy_bind_size: 0
+ export_off: 16504
+ export_size: 152
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 16664
+ nsyms: 14
+ stroff: 16888
+ strsize: 320
+ - cmd: LC_DYSYMTAB
+ cmdsize: 80
+ ilocalsym: 0
+ nlocalsym: 2
+ iextdefsym: 2
+ nextdefsym: 8
+ iundefsym: 10
+ nundefsym: 4
+ tocoff: 0
+ ntoc: 0
+ modtaboff: 0
+ nmodtab: 0
+ extrefsymoff: 0
+ nextrefsyms: 0
+ indirectsymoff: 0
+ nindirectsyms: 0
+ extreloff: 0
+ nextrel: 0
+ locreloff: 0
+ nlocrel: 0
+ - cmd: LC_ID_DYLIB
+ cmdsize: 112
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '/System/Library/Frameworks/Availability.framework/Versions/A/Availability'
+ ZeroPadBytes: 7
+ - cmd: LC_UUID
+ cmdsize: 24
+ uuid: 4C4C4470-5555-3144-A142-4EE44DA08D2F
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 4
+ version: 1245184
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 14942208
+ compatibility_version: 65536
+ Content: '/usr/lib/libobjc.A.dylib'
+ ZeroPadBytes: 8
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 88473600
+ compatibility_version: 65536
+ Content: '/usr/lib/libSystem.B.dylib'
+ ZeroPadBytes: 6
+ - cmd: LC_FUNCTION_STARTS
+ cmdsize: 16
+ dataoff: 16656
+ datasize: 8
+ - cmd: LC_DATA_IN_CODE
+ cmdsize: 16
+ dataoff: 16664
+ datasize: 0
+LinkEditData:
+ RebaseOpcodes:
+ - Opcode: REBASE_OPCODE_SET_TYPE_IMM
+ Imm: 1
+ - Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ Imm: 1
+ ExtraData: [ 0x0 ]
+ - Opcode: REBASE_OPCODE_DO_REBASE_IMM_TIMES
+ Imm: 1
+ - Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ Imm: 2
+ ExtraData: [ 0x18 ]
+ - Opcode: REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
+ Imm: 0
+ ExtraData: [ 0x2, 0x40 ]
+ - Opcode: REBASE_OPCODE_ADD_ADDR_IMM_SCALED
+ Imm: 1
+ - Opcode: REBASE_OPCODE_DO_REBASE_IMM_TIMES
+ Imm: 2
+ - Opcode: REBASE_OPCODE_ADD_ADDR_IMM_SCALED
+ Imm: 3
+ - Opcode: REBASE_OPCODE_DO_REBASE_IMM_TIMES
+ Imm: 1
+ - Opcode: REBASE_OPCODE_DONE
+ Imm: 0
+ BindOpcodes:
+ - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+ Imm: 0
+ Symbol: '_OBJC_METACLASS_$_NSObject'
+ - Opcode: BIND_OPCODE_SET_TYPE_IMM
+ Imm: 1
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+ Imm: 1
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ Imm: 2
+ ULEBExtraData: [ 0x90 ]
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DO_BIND
+ Imm: 0
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DO_BIND
+ Imm: 0
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+ Imm: 0
+ Symbol: __objc_empty_cache
+ - Opcode: BIND_OPCODE_SET_TYPE_IMM
+ Imm: 1
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DO_BIND
+ Imm: 0
+ Symbol: ''
+ - Opcode: BIND_OPCODE_ADD_ADDR_ULEB
+ Imm: 0
+ ULEBExtraData: [ 0x20 ]
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DO_BIND
+ Imm: 0
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+ Imm: 0
+ Symbol: '_OBJC_CLASS_$_NSObject'
+ - Opcode: BIND_OPCODE_SET_TYPE_IMM
+ Imm: 1
+ Symbol: ''
+ - Opcode: BIND_OPCODE_ADD_ADDR_ULEB
+ Imm: 0
+ ULEBExtraData: [ 0xFFFFFFFFFFFFFFF0 ]
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DO_BIND
+ Imm: 0
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DONE
+ Imm: 0
+ Symbol: ''
+ ExportTrie:
+ TerminalSize: 0
+ NodeOffset: 0
+ Name: ''
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 0
+ NodeOffset: 5
+ Name: _
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 0
+ NodeOffset: 17
+ Name: OBJC_
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 3
+ NodeOffset: 49
+ Name: 'METACLASS_$_Foo'
+ Flags: 0x0
+ Address: 0x3090
+ Other: 0x0
+ ImportName: ''
+ - TerminalSize: 3
+ NodeOffset: 54
+ Name: 'CLASS_$_Foo'
+ Flags: 0x0
+ Address: 0x30B8
+ Other: 0x0
+ ImportName: ''
+ - TerminalSize: 0
+ NodeOffset: 59
+ Name: p
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 3
+ NodeOffset: 104
+ Name: rivateGlobalVariable
+ Flags: 0x0
+ Address: 0x30E0
+ Other: 0x0
+ ImportName: ''
+ - TerminalSize: 3
+ NodeOffset: 109
+ Name: ublicGlobalVariable
+ Flags: 0x0
+ Address: 0x30E4
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 3
+ NodeOffset: 130
+ Name: '4'
+ Flags: 0x0
+ Address: 0x30F0
+ Other: 0x0
+ ImportName: ''
+ - TerminalSize: 3
+ NodeOffset: 135
+ Name: '3'
+ Flags: 0x0
+ Address: 0x30EC
+ Other: 0x0
+ ImportName: ''
+ - TerminalSize: 3
+ NodeOffset: 140
+ Name: '2'
+ Flags: 0x0
+ Address: 0x30E8
+ Other: 0x0
+ ImportName: ''
+ - TerminalSize: 3
+ NodeOffset: 145
+ Name: '6'
+ Flags: 0x0
+ Address: 0x30F4
+ Other: 0x0
+ ImportName: ''
+ NameList:
+ - n_strx: 2
+ n_type: 0xE
+ n_sect: 5
+ n_desc: 0
+ n_value: 12288
+ - n_strx: 28
+ n_type: 0xE
+ n_sect: 5
+ n_desc: 0
+ n_value: 12360
+ - n_strx: 50
+ n_type: 0xF
+ n_sect: 7
+ n_desc: 0
+ n_value: 12512
+ - n_strx: 73
+ n_type: 0xF
+ n_sect: 7
+ n_desc: 0
+ n_value: 12516
+ - n_strx: 95
+ n_type: 0xF
+ n_sect: 7
+ n_desc: 0
+ n_value: 12520
+ - n_strx: 118
+ n_type: 0xF
+ n_sect: 7
+ n_desc: 0
+ n_value: 12524
+ - n_strx: 141
+ n_type: 0xF
+ n_sect: 7
+ n_desc: 0
+ n_value: 12528
+ - n_strx: 164
+ n_type: 0xF
+ n_sect: 7
+ n_desc: 0
+ n_value: 12532
+ - n_strx: 187
+ n_type: 0xF
+ n_sect: 6
+ n_desc: 0
+ n_value: 12432
+ - n_strx: 209
+ n_type: 0xF
+ n_sect: 6
+ n_desc: 0
+ n_value: 12472
+ - n_strx: 227
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 256
+ n_value: 0
+ - n_strx: 250
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 256
+ n_value: 0
+ - n_strx: 277
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 256
+ n_value: 0
+ - n_strx: 296
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 512
+ n_value: 0
+ StringTable:
+ - ' '
+ - '__OBJC_METACLASS_RO_$_Foo'
+ - '__OBJC_CLASS_RO_$_Foo'
+ - _privateGlobalVariable
+ - _publicGlobalVariable
+ - _publicGlobalVariable2
+ - _publicGlobalVariable3
+ - _publicGlobalVariable4
+ - _publicGlobalVariable6
+ - '_OBJC_METACLASS_$_Foo'
+ - '_OBJC_CLASS_$_Foo'
+ - '_OBJC_CLASS_$_NSObject'
+ - '_OBJC_METACLASS_$_NSObject'
+ - __objc_empty_cache
+ - dyld_stub_binder
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+...
diff --git a/clang/test/InstallAPI/diagnostics-cpp.test b/clang/test/InstallAPI/diagnostics-cpp.test
new file mode 100644
index 00000000000000..f08d4f596c4fb3
--- /dev/null
+++ b/clang/test/InstallAPI/diagnostics-cpp.test
@@ -0,0 +1,461 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json
+
+// RUN: yaml2obj %t/Mismatch.yaml -o %t/System/Library/Frameworks/MismatchCpp.framework/MismatchCpp
+
+// RUN: not clang-installapi --target=arm64-apple-macos13 -x objective-c++ \
+// RUN: -F %t/System/Library/Frameworks \
+// RUN: -install_name /System/Library/Frameworks/MismatchCpp.framework/Versions/A/MismatchCpp \
+// RUN: -current_version 1 -compatibility_version 1 %t/inputs.json \
+// RUN: --verify-against=%t/System/Library/Frameworks/MismatchCpp.framework/MismatchCpp \
+// RUN: --verify-mode=Pedantic -o output.tbd --demangle 2>&1 | FileCheck %s
+
+CHECK: warning: violations found for arm64-apple-macos13
+CHECK: CPP.h:5:7: error: declaration has external linkage, but symbol has internal linkage in dynamic library 'vtable for Bar'
+CHECK-NEXT: class Bar : Foo {
+CHECK-NEXT: ^
+CHECK-NEXT: CPP.h:5:7: error: declaration has external linkage, but symbol has internal linkage in dynamic library 'typeinfo for Bar'
+CHECK-NEXT: CPP.h:5:7: error: declaration has external linkage, but symbol has internal linkage in dynamic library 'typeinfo name for Bar'
+CHECK-NEXT: CPP.h:6:7: error: dynamic library symbol '(weak-def) Bar::init()' is weak defined, but its declaration is not
+CHECK-NEXT: int init();
+CHECK-NEXT: ^
+
+//--- inputs.json.in
+{
+ "headers": [ {
+ "path" : "DSTROOT/System/Library/Frameworks/MismatchCpp.framework/Headers/CPP.h",
+ "type" : "public"
+ }
+ ],
+ "version": "3"
+}
+
+//--- System/Library/Frameworks/MismatchCpp.framework/Headers/CPP.h
+class Foo {
+ virtual int init() = 0;
+};
+
+class Bar : Foo {
+ int init();
+};
+
+/// Created from:
+// With LD flags: -exported_symbol,"__ZN3Bar4initEv" -exported_symbol,"__Z3fooIjEiT_"
+// class Foo { virtual int init() = 0;};
+//
+// class Bar : Foo {int init() { return 1;}};
+// Bar bar;
+//
+// template <typename T> int foo(T val) { return 1; }
+// template <> int foo(unsigned val) { return 1; }
+
+//--- Mismatch.yaml
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x100000C
+ cpusubtype: 0x0
+ filetype: 0x6
+ ncmds: 15
+ sizeofcmds: 1224
+ flags: 0x118085
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 312
+ segname: __TEXT
+ vmaddr: 0
+ vmsize: 16384
+ fileoff: 0
+ filesize: 16384
+ maxprot: 5
+ initprot: 5
+ nsects: 3
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0x10E8
+ size: 16
+ offset: 0x10E8
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000400
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 20008052C0035FD620008052C0035FD6
+ - sectname: __const
+ segname: __TEXT
+ addr: 0x10F8
+ size: 10
+ offset: 0x10F8
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 334261720033466F6F00
+ - sectname: __unwind_info
+ segname: __TEXT
+ addr: 0x1104
+ size: 4152
+ offset: 0x1104
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 010000001C000000010000002000000000000000200000000200000000000002E81000003800000038000000F81000000000000038000000030000000C0001001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: __DATA_CONST
+ vmaddr: 16384
+ vmsize: 16384
+ fileoff: 16384
+ filesize: 16384
+ maxprot: 3
+ initprot: 3
+ nsects: 2
+ flags: 16
+ Sections:
+ - sectname: __const
+ segname: __DATA_CONST
+ addr: 0x4000
+ size: 80
+ offset: 0x4000
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 00000000000000002840000000000000F0100000000000001000000000000000FD100000000000801000000000000000F810000000000080000000000100000018400000000000000000000000000000
+ - sectname: __objc_imageinfo
+ segname: __DATA_CONST
+ addr: 0x4050
+ size: 8
+ offset: 0x4050
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '0000000040000000'
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __DATA
+ vmaddr: 32768
+ vmsize: 16384
+ fileoff: 32768
+ filesize: 16384
+ maxprot: 3
+ initprot: 3
+ nsects: 1
+ flags: 0
+ Sections:
+ - sectname: __data
+ segname: __DATA
+ addr: 0x8000
+ size: 8
+ offset: 0x8000
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '1040000000000000'
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __LINKEDIT
+ vmaddr: 49152
+ vmsize: 1104
+ fileoff: 49152
+ filesize: 1104
+ maxprot: 1
+ initprot: 1
+ nsects: 0
+ flags: 0
+ - cmd: LC_DYLD_INFO_ONLY
+ cmdsize: 48
+ rebase_off: 49152
+ rebase_size: 16
+ bind_off: 49168
+ bind_size: 96
+ weak_bind_off: 49264
+ weak_bind_size: 24
+ lazy_bind_off: 0
+ lazy_bind_size: 0
+ export_off: 49288
+ export_size: 48
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 49344
+ nsyms: 11
+ stroff: 49520
+ strsize: 192
+ - cmd: LC_DYSYMTAB
+ cmdsize: 80
+ ilocalsym: 0
+ nlocalsym: 6
+ iextdefsym: 6
+ nextdefsym: 2
+ iundefsym: 8
+ nundefsym: 3
+ tocoff: 0
+ ntoc: 0
+ modtaboff: 0
+ nmodtab: 0
+ extrefsymoff: 0
+ nextrefsyms: 0
+ indirectsymoff: 0
+ nindirectsyms: 0
+ extreloff: 0
+ nextrel: 0
+ locreloff: 0
+ nlocrel: 0
+ - cmd: LC_ID_DYLIB
+ cmdsize: 96
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '/System/Library/Frameworks/MismatchCpp.framework/Versions/A/MismatchCpp'
+ ZeroPadBytes: 1
+ - cmd: LC_UUID
+ cmdsize: 24
+ uuid: 4C4C44F3-5555-3144-A13F-B3FE15787197
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 4
+ version: 1245184
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 48
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 117985024
+ compatibility_version: 65536
+ Content: '/usr/lib/libc++.1.dylib'
+ ZeroPadBytes: 1
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 88473600
+ compatibility_version: 65536
+ Content: '/usr/lib/libSystem.B.dylib'
+ ZeroPadBytes: 6
+ - cmd: LC_FUNCTION_STARTS
+ cmdsize: 16
+ dataoff: 49336
+ datasize: 8
+ - cmd: LC_DATA_IN_CODE
+ cmdsize: 16
+ dataoff: 49344
+ datasize: 0
+ - cmd: LC_CODE_SIGNATURE
+ cmdsize: 16
+ dataoff: 49712
+ datasize: 544
+LinkEditData:
+ RebaseOpcodes:
+ - Opcode: REBASE_OPCODE_SET_TYPE_IMM
+ Imm: 1
+ - Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ Imm: 1
+ ExtraData: [ 0x8 ]
+ - Opcode: REBASE_OPCODE_DO_REBASE_IMM_TIMES
+ Imm: 2
+ - Opcode: REBASE_OPCODE_ADD_ADDR_IMM_SCALED
+ Imm: 1
+ - Opcode: REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
+ Imm: 0
+ ExtraData: [ 0x3, 0x8 ]
+ - Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ Imm: 2
+ ExtraData: [ 0x0 ]
+ - Opcode: REBASE_OPCODE_DO_REBASE_IMM_TIMES
+ Imm: 1
+ - Opcode: REBASE_OPCODE_DONE
+ Imm: 0
+ BindOpcodes:
+ - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+ Imm: 0
+ Symbol: __ZTVN10__cxxabiv117__class_type_infoE
+ - Opcode: BIND_OPCODE_SET_TYPE_IMM
+ Imm: 1
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+ Imm: 1
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ Imm: 1
+ ULEBExtraData: [ 0x18 ]
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_ADDEND_SLEB
+ Imm: 0
+ SLEBExtraData: [ 16 ]
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DO_BIND
+ Imm: 0
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+ Imm: 0
+ Symbol: __ZTVN10__cxxabiv121__vmi_class_type_infoE
+ - Opcode: BIND_OPCODE_SET_TYPE_IMM
+ Imm: 1
+ Symbol: ''
+ - Opcode: BIND_OPCODE_ADD_ADDR_ULEB
+ Imm: 0
+ ULEBExtraData: [ 0x8 ]
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DO_BIND
+ Imm: 0
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DONE
+ Imm: 0
+ Symbol: ''
+ WeakBindOpcodes:
+ - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+ Imm: 0
+ Symbol: __ZN3Bar4initEv
+ - Opcode: BIND_OPCODE_SET_TYPE_IMM
+ Imm: 1
+ Symbol: ''
+ - Opcode: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ Imm: 1
+ ULEBExtraData: [ 0x10 ]
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DO_BIND
+ Imm: 0
+ Symbol: ''
+ - Opcode: BIND_OPCODE_DONE
+ Imm: 0
+ Symbol: ''
+ ExportTrie:
+ TerminalSize: 0
+ NodeOffset: 0
+ Name: ''
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 0
+ NodeOffset: 7
+ Name: __Z
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 3
+ NodeOffset: 35
+ Name: 3fooIjEiT_
+ Flags: 0x0
+ Address: 0x10E8
+ Other: 0x0
+ ImportName: ''
+ - TerminalSize: 3
+ NodeOffset: 40
+ Name: N3Bar4initEv
+ Flags: 0x4
+ Address: 0x10F0
+ Other: 0x0
+ ImportName: ''
+ NameList:
+ - n_strx: 32
+ n_type: 0x1E
+ n_sect: 4
+ n_desc: 0
+ n_value: 16384
+ - n_strx: 42
+ n_type: 0x1E
+ n_sect: 4
+ n_desc: 0
+ n_value: 16408
+ - n_strx: 52
+ n_type: 0x1E
+ n_sect: 4
+ n_desc: 0
+ n_value: 16424
+ - n_strx: 62
+ n_type: 0x1E
+ n_sect: 6
+ n_desc: 0
+ n_value: 32768
+ - n_strx: 67
+ n_type: 0x1E
+ n_sect: 2
+ n_desc: 0
+ n_value: 4344
+ - n_strx: 77
+ n_type: 0x1E
+ n_sect: 2
+ n_desc: 0
+ n_value: 4349
+ - n_strx: 2
+ n_type: 0xF
+ n_sect: 1
+ n_desc: 0
+ n_value: 4328
+ - n_strx: 16
+ n_type: 0xF
+ n_sect: 1
+ n_desc: 128
+ n_value: 4336
+ - n_strx: 87
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 256
+ n_value: 0
+ - n_strx: 126
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 256
+ n_value: 0
+ - n_strx: 169
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 512
+ n_value: 0
+ StringTable:
+ - ' '
+ - __Z3fooIjEiT_
+ - __ZN3Bar4initEv
+ - __ZTV3Bar
+ - __ZTI3Foo
+ - __ZTI3Bar
+ - _bar
+ - __ZTS3Bar
+ - __ZTS3Foo
+ - __ZTVN10__cxxabiv117__class_type_infoE
+ - __ZTVN10__cxxabiv121__vmi_class_type_infoE
+ - dyld_stub_binder
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ FunctionStarts: [ 0x10E8, 0x10F0 ]
+...
diff --git a/clang/test/InstallAPI/hiddens.test b/clang/test/InstallAPI/hiddens.test
new file mode 100644
index 00000000000000..b3196ef945cd12
--- /dev/null
+++ b/clang/test/InstallAPI/hiddens.test
@@ -0,0 +1,262 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json
+
+// RUN: yaml2obj %t/Hidden.yaml -o %t/System/Library/Frameworks/Hidden.framework/Hidden
+
+// RUN: clang-installapi --target=x86_64-apple-macos13 -x objective-c \
+// RUN: -F %t/System/Library/Frameworks \
+// RUN: -install_name /System/Library/Frameworks/Hidden.framework/Versions/A/Hidden\
+// RUN: -current_version 1 -compatibility_version 1 %t/inputs.json \
+// RUN: --verify-against=%t/System/Library/Frameworks/Hidden.framework/Hidden \
+// RUN: --verify-mode=Pedantic -o %t/output.tbd 2>&1 | FileCheck %s
+
+// CHECK-NOT: error
+// CHECK: warning: use of __private_extern__
+
+// RUN: llvm-readtapi --compare %t/output.tbd %t/expected.tbd
+
+//--- inputs.json.in
+{
+ "headers": [ {
+ "path" : "DSTROOT/System/Library/Frameworks/Hidden.framework/Headers/Hidden.h",
+ "type" : "public"
+ }
+ ],
+ "version": "3"
+}
+
+//--- System/Library/Frameworks/Hidden.framework/Headers/Hidden.h
+__private_extern__ int foo(); // Clang doesn't warn on this, but should.
+__private_extern__ int baz;
+__attribute__((visibility("hidden"))) int bar();
+
+/// Created from:
+/// #import "Hidden.h" int foo(void) { return 1; } int bar(void) { return 1; }
+//--- Hidden.yaml
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x1000007
+ cpusubtype: 0x3
+ filetype: 0x6
+ ncmds: 12
+ sizeofcmds: 920
+ flags: 0x100085
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 312
+ segname: __TEXT
+ vmaddr: 0
+ vmsize: 8192
+ fileoff: 0
+ filesize: 8192
+ maxprot: 5
+ initprot: 5
+ nsects: 3
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0xBB8
+ size: 22
+ offset: 0xBB8
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000400
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 554889E5B8010000005DC3554889E5B8010000005DC3
+ - sectname: __unwind_info
+ segname: __TEXT
+ addr: 0xBD0
+ size: 4152
+ offset: 0xBD0
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 010000001C000000010000002000000000000000200000000200000000000001B80B00003800000038000000CE0B00000000000038000000030000000C0001001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ - sectname: __eh_frame
+ segname: __TEXT
+ addr: 0x1C08
+ size: 24
+ offset: 0x1C08
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x6000000B
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 1400000000000000017A520001781001100C070890010000
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __DATA_CONST
+ vmaddr: 8192
+ vmsize: 4096
+ fileoff: 8192
+ filesize: 4096
+ maxprot: 3
+ initprot: 3
+ nsects: 1
+ flags: 16
+ Sections:
+ - sectname: __objc_imageinfo
+ segname: __DATA_CONST
+ addr: 0x2000
+ size: 8
+ offset: 0x2000
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '0000000040000000'
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __LINKEDIT
+ vmaddr: 12288
+ vmsize: 104
+ fileoff: 12288
+ filesize: 104
+ maxprot: 1
+ initprot: 1
+ nsects: 0
+ flags: 0
+ - cmd: LC_DYLD_INFO_ONLY
+ cmdsize: 48
+ rebase_off: 0
+ rebase_size: 0
+ bind_off: 0
+ bind_size: 0
+ weak_bind_off: 0
+ weak_bind_size: 0
+ lazy_bind_off: 0
+ lazy_bind_size: 0
+ export_off: 12288
+ export_size: 16
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 12312
+ nsyms: 3
+ stroff: 12360
+ strsize: 32
+ - cmd: LC_DYSYMTAB
+ cmdsize: 80
+ ilocalsym: 0
+ nlocalsym: 1
+ iextdefsym: 1
+ nextdefsym: 1
+ iundefsym: 2
+ nundefsym: 1
+ tocoff: 0
+ ntoc: 0
+ modtaboff: 0
+ nmodtab: 0
+ extrefsymoff: 0
+ nextrefsyms: 0
+ indirectsymoff: 0
+ nindirectsyms: 0
+ extreloff: 0
+ nextrel: 0
+ locreloff: 0
+ nlocrel: 0
+ - cmd: LC_ID_DYLIB
+ cmdsize: 88
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '/System/Library/Frameworks/Hidden.framework/Versions/A/Hidden'
+ ZeroPadBytes: 3
+ - cmd: LC_UUID
+ cmdsize: 24
+ uuid: 4C4C44E7-5555-3144-A133-0271E799C487
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 4
+ version: 1245184
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 88473600
+ compatibility_version: 65536
+ Content: '/usr/lib/libSystem.B.dylib'
+ ZeroPadBytes: 6
+ - cmd: LC_FUNCTION_STARTS
+ cmdsize: 16
+ dataoff: 12304
+ datasize: 8
+ - cmd: LC_DATA_IN_CODE
+ cmdsize: 16
+ dataoff: 12312
+ datasize: 0
+LinkEditData:
+ ExportTrie:
+ TerminalSize: 0
+ NodeOffset: 0
+ Name: ''
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 3
+ NodeOffset: 8
+ Name: _foo
+ Flags: 0x0
+ Address: 0xBB8
+ Other: 0x0
+ ImportName: ''
+ NameList:
+ - n_strx: 7
+ n_type: 0x1E
+ n_sect: 1
+ n_desc: 0
+ n_value: 3011
+ - n_strx: 2
+ n_type: 0xF
+ n_sect: 1
+ n_desc: 0
+ n_value: 3000
+ - n_strx: 12
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 256
+ n_value: 0
+ StringTable:
+ - ' '
+ - _foo
+ - _bar
+ - dyld_stub_binder
+ - ''
+ - ''
+ - ''
+ FunctionStarts: [ 0xBB8, 0xBC3 ]
+...
+
+//--- expected.tbd
+--- !tapi-tbd
+tbd-version: 4
+targets: [ x86_64-macos ]
+flags: [ not_app_extension_safe ]
+install-name: '/System/Library/Frameworks/Hidden.framework/Versions/A/Hidden'
+...
+
diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp b/clang/tools/clang-installapi/ClangInstallAPI.cpp
index d758f731179008..54e82d78d4d228 100644
--- a/clang/tools/clang-installapi/ClangInstallAPI.cpp
+++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp
@@ -111,17 +111,15 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
// Execute and gather AST results.
// An invocation is ran for each unique target triple and for each header
// access level.
- Records FrontendResults;
for (const auto &[Targ, Trip] : Opts.DriverOpts.Targets) {
+ Ctx.Verifier->setTarget(Targ);
+ Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);
for (const HeaderType Type :
{HeaderType::Public, HeaderType::Private, HeaderType::Project}) {
- Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);
- Ctx.Verifier->setTarget(Targ);
Ctx.Type = Type;
if (!runFrontend(ProgName, Opts.DriverOpts.Verbose, Ctx,
InMemoryFileSystem.get(), Opts.getClangFrontendArgs()))
return EXIT_FAILURE;
- FrontendResults.emplace_back(std::move(Ctx.Slice));
}
}
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
index e5ff8a1aaa4fe5..b8696bb7896d86 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -261,6 +261,9 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
if (!processFrontendOptions(ArgList))
return;
+ /// Force cc1 options that should always be on.
+ FrontendArgs = {"-fsyntax-only", "-Wprivate-extern"};
+
/// Any unclaimed arguments should be handled by invoking the clang frontend.
for (const Arg *A : ArgList) {
if (A->isClaimed())
@@ -268,7 +271,6 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
FrontendArgs.emplace_back(A->getSpelling());
llvm::copy(A->getValues(), std::back_inserter(FrontendArgs));
}
- FrontendArgs.push_back("-fsyntax-only");
}
InstallAPIContext Options::createContext() {
>From ac25849bbbd3aadd77c19a56da976f5f6fee5ceb Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ishida at apple.com>
Date: Sat, 16 Mar 2024 13:05:55 -0700
Subject: [PATCH 2/2] Add DiagnosticGroup for installapi warnings
---
clang/include/clang/Basic/DiagnosticGroups.td | 4 ++++
.../clang/Basic/DiagnosticInstallAPIKinds.td | 14 +++++++-------
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index f5ff89111d1110..dee555f783cc45 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1508,3 +1508,7 @@ def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;
// Warnings and fixes to support the "safe buffers" programming model.
def UnsafeBufferUsageInContainer : DiagGroup<"unsafe-buffer-usage-in-container">;
def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer]>;
+
+// Warnings and notes InstallAPI verification.
+def InstallAPIViolation : DiagGroup<"installapi-violation">;
+
diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
index 5ed2e23425dc5f..f99a5fca64cb46 100644
--- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
+++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
@@ -18,22 +18,22 @@ def err_no_output_file: Error<"no output file specified">;
} // end of command line category.
let CategoryName = "Verification" in {
-def warn_target: Warning<"violations found for %0">;
+def warn_target: Warning<"violations found for %0">, InGroup<InstallAPIViolation>;
def err_library_missing_symbol : Error<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">;
-def warn_library_missing_symbol : Warning<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">;
+def warn_library_missing_symbol : Warning<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">, InGroup<InstallAPIViolation>;
def err_library_hidden_symbol : Error<"declaration has external linkage, but symbol has internal linkage in dynamic library '%0'">;
-def warn_library_hidden_symbol : Warning<"declaration has external linkage, but symbol has internal linkage in dynamic library '%0'">;
-def warn_header_hidden_symbol : Warning<"symbol exported in dynamic library, but marked hidden in declaration '%0'">;
+def warn_library_hidden_symbol : Warning<"declaration has external linkage, but symbol has internal linkage in dynamic library '%0'">, InGroup<InstallAPIViolation>;
+def warn_header_hidden_symbol : Warning<"symbol exported in dynamic library, but marked hidden in declaration '%0'">, InGroup<InstallAPIViolation>;
def err_header_hidden_symbol : Error<"symbol exported in dynamic library, but marked hidden in declaration '%0'">;
def err_header_symbol_missing : Error<"no declaration found for exported symbol '%0' in dynamic library">;
def warn_header_availability_mismatch : Warning<"declaration '%0' is marked %select{available|unavailable}1,"
- " but symbol is %select{not |}2exported in dynamic library">;
+ " but symbol is %select{not |}2exported in dynamic library">, InGroup<InstallAPIViolation>;
def err_header_availability_mismatch : Error<"declaration '%0' is marked %select{available|unavailable}1,"
" but symbol is %select{not |}2exported in dynamic library">;
def warn_dylib_symbol_flags_mismatch : Warning<"dynamic library symbol '%0' is "
- "%select{weak defined|thread local}1, but its declaration is not">;
+ "%select{weak defined|thread local}1, but its declaration is not">, InGroup<InstallAPIViolation>;
def warn_header_symbol_flags_mismatch : Warning<"declaration '%0' is "
- "%select{weak defined|thread local}1, but symbol is not in dynamic library">;
+ "%select{weak defined|thread local}1, but symbol is not in dynamic library">, InGroup<InstallAPIViolation>;
def err_dylib_symbol_flags_mismatch : Error<"dynamic library symbol '%0' is "
"%select{weak defined|thread local}1, but its declaration is not">;
def err_header_symbol_flags_mismatch : Error<"declaration '%0' is "
More information about the cfe-commits
mailing list