diff --git a/rs_bindings_from_cc/decl_importer.h b/rs_bindings_from_cc/decl_importer.h index 0a73fc64c..d56e2cf81 100644 --- a/rs_bindings_from_cc/decl_importer.h +++ b/rs_bindings_from_cc/decl_importer.h @@ -35,7 +35,9 @@ class Invocation { Invocation( BazelLabel target, absl::Span public_headers, const absl::flat_hash_map& header_targets, - std::optional> do_not_bind_allowlist) + std::optional> do_not_bind_allowlist, + absl::flat_hash_map> + crubit_features) : target_(target), public_headers_(public_headers), lifetime_context_(std::make_shared< @@ -49,6 +51,7 @@ class Invocation { ir_.public_headers.insert(ir_.public_headers.end(), public_headers_.begin(), public_headers.end()); ir_.current_target = target_; + ir_.crubit_features = std::move(crubit_features); } // Returns the target of a header, if any. @@ -161,6 +164,9 @@ class ImportContext { // other redeclarations of the decl. virtual bool IsFromProtoTarget(const clang::Decl& decl) const = 0; + // Returns true iff `label` has opted in to crubit support. + virtual bool IsCrubitEnabledForTarget(const BazelLabel& label) const = 0; + // Gets an IR UnqualifiedIdentifier for the named decl. // // If the decl's name is an identifier, this returns that identifier as-is. diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc index 54b19941a..807b5a2b9 100644 --- a/rs_bindings_from_cc/importer.cc +++ b/rs_bindings_from_cc/importer.cc @@ -891,6 +891,20 @@ bool Importer::IsFromProtoTarget(const clang::Decl& decl) const { return filename.has_value() && filename->ends_with(".proto.h"); } +bool Importer::IsCrubitEnabledForTarget(const BazelLabel& label) const { + if (auto i = invocation_.ir_.crubit_features.find(label); + i != invocation_.ir_.crubit_features.end()) { + return !i->second.empty(); + } + // DO NOT SUBMIT: this should have a proper target assignment. + if (label.value().find("support") == std::string::npos) { + // fprintf(stderr, "Crubit is not enabled for target %s\n", + // label.value().c_str()); + return false; + } + return true; +} + IR::Item Importer::HardError(const clang::Decl& decl, FormattedError error) { return ImportUnsupportedItem(decl, std::nullopt, {error}, /*is_hard_error=*/true); @@ -1061,6 +1075,16 @@ absl::StatusOr Importer::ConvertTemplateSpecializationType( type_string)); } + if (auto* template_decl = type->getTemplateName().getAsTemplateDecl()) { + auto target = GetOwningTarget(template_decl); + if (!IsCrubitEnabledForTarget(target)) { + return absl::InvalidArgumentError(absl::Substitute( + "Failed to complete template specialization type $0: template " + "belongs to target $1, which does not support Crubit.", + type_string, target.value())); + } + } + if (HasBeenAlreadySuccessfullyImported(specialization_decl)) return ConvertTypeDecl(specialization_decl); diff --git a/rs_bindings_from_cc/importer.h b/rs_bindings_from_cc/importer.h index 1c87a8b83..e4881e87f 100644 --- a/rs_bindings_from_cc/importer.h +++ b/rs_bindings_from_cc/importer.h @@ -116,6 +116,7 @@ class Importer final : public ImportContext { BazelLabel GetOwningTarget(const clang::Decl* decl) const override; bool IsFromCurrentTarget(const clang::Decl* decl) const override; bool IsFromProtoTarget(const clang::Decl& decl) const override; + bool IsCrubitEnabledForTarget(const BazelLabel& label) const override; absl::StatusOr GetTranslatedName( const clang::NamedDecl* named_decl) const override; absl::StatusOr GetTranslatedIdentifier( diff --git a/rs_bindings_from_cc/ir_from_cc.cc b/rs_bindings_from_cc/ir_from_cc.cc index ecc519b3a..19a7c8bd4 100644 --- a/rs_bindings_from_cc/ir_from_cc.cc +++ b/rs_bindings_from_cc/ir_from_cc.cc @@ -220,7 +220,8 @@ absl::StatusOr IrFromCc(IrFromCcOptions options) { Invocation invocation(options.current_target, augmented_public_headers, options.headers_to_targets, - std::move(options.do_not_bind_allowlist)); + std::move(options.do_not_bind_allowlist), + std::move(options.crubit_features)); if (!clang::tooling::runToolOnCodeWithArgs( std::make_unique(invocation), virtual_input_file_content, args_as_strings, @@ -238,7 +239,6 @@ absl::StatusOr IrFromCc(IrFromCcOptions options) { !status.ok()) { return status; } - invocation.ir_.crubit_features = std::move(options.crubit_features); return invocation.ir_; } diff --git a/rs_bindings_from_cc/recording_diagnostic_consumer.cc b/rs_bindings_from_cc/recording_diagnostic_consumer.cc index ec5aed345..a48885f23 100644 --- a/rs_bindings_from_cc/recording_diagnostic_consumer.cc +++ b/rs_bindings_from_cc/recording_diagnostic_consumer.cc @@ -101,6 +101,10 @@ std::string RecordingDiagnosticConsumer::ConcatenatedDiagnostics( RecordingDiagnosticConsumer RecordDiagnostics( clang::DiagnosticsEngine& diagnostic_engine, std::function callback) { + // Reset the diagnostic engine to a known state. In particular, if there were + // too many diagnostics reported previously (even in sfinae contexts), + // the diagnostic engine's fatal bit will get stuck on. + diagnostic_engine.Reset(/*soft=*/true); RecordingDiagnosticConsumer diagnostic_recorder; std::unique_ptr original_consumer = diagnostic_engine.takeClient();