Further tweaks for deterministic order of IR items.

PiperOrigin-RevId: 426507636
diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc
index 35af0f6..35ad45f 100644
--- a/rs_bindings_from_cc/importer.cc
+++ b/rs_bindings_from_cc/importer.cc
@@ -39,6 +39,7 @@
 #include "third_party/llvm/llvm-project/clang/include/clang/AST/RecordLayout.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/Basic/FileManager.h"
+#include "third_party/llvm/llvm-project/clang/include/clang/Basic/OperatorKinds.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceLocation.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceManager.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/Basic/Specifiers.h"
@@ -219,6 +220,37 @@
   return result;
 }
 
+// Multiple IR items can be associated with the same source location (e.g. the
+// implicitly defined constructors and assignment operators). To produce
+// deterministic output, we order such items based on GetDeclOrder.  The order
+// is somewhat arbitrary, but we still try to make it aesthetically pleasing
+// (e.g. constructors go before assignment operators;  default constructor goes
+// first, etc.).
+static int GetDeclOrder(const clang::Decl* decl) {
+  if (clang::isa<clang::RecordDecl>(decl)) {
+    return decl->getDeclContext()->isRecord() ? 101 : 100;
+  }
+
+  if (auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
+    return ctor->isDefaultConstructor() ? 202
+           : ctor->isCopyConstructor()  ? 203
+           : ctor->isMoveConstructor()  ? 204
+                                        : 299;
+  }
+
+  if (clang::isa<clang::CXXDestructorDecl>(decl)) {
+    return 306;
+  }
+
+  if (auto* method = clang::dyn_cast<clang::CXXMethodDecl>(decl)) {
+    return method->isCopyAssignmentOperator()   ? 401
+           : method->isMoveAssignmentOperator() ? 402
+                                                : 499;
+  }
+
+  return 999;
+}
+
 void Importer::Import(clang::TranslationUnitDecl* translation_unit_decl) {
   ImportDeclsFromDeclContext(translation_unit_decl);
 
@@ -227,7 +259,6 @@
   auto is_less_than = [&sm](const OrderedItem& a, const OrderedItem& b) {
     auto a_range = std::get<0>(a);
     auto b_range = std::get<0>(b);
-
     if (!a_range.isValid() || !b_range.isValid()) {
       if (a_range.isValid() != b_range.isValid())
         return !a_range.isValid() && b_range.isValid();
@@ -240,57 +271,85 @@
         return sm.isBeforeInTranslationUnit(a_range.getEnd(), b_range.getEnd());
       }
     }
-    return std::get<1>(a) < std::get<1>(b);
+
+    auto a_decl_order = std::get<1>(a);
+    auto b_decl_order = std::get<1>(b);
+    if (a_decl_order != b_decl_order) return a_decl_order < b_decl_order;
+
+    // A single FunctionDecl can be associated with multiple UnsupportedItems.
+    // Comparing the fields allows deterministic order between items like:
+    // Non-trivial_abi type '...' is not supported by value as a parameter.
+    // Non-trivial_abi type '...' is not supported by value as a return type.
+    const auto& a_variant = std::get<2>(a);
+    const auto& b_variant = std::get<2>(b);
+    const auto* a_unsupported = std::get_if<UnsupportedItem>(&a_variant);
+    const auto* b_unsupported = std::get_if<UnsupportedItem>(&b_variant);
+    if (a_unsupported && b_unsupported) {
+      if (a_unsupported->name != b_unsupported->name)
+        return a_unsupported->name < b_unsupported->name;
+      return a_unsupported->message < b_unsupported->message;
+    }
+
+    return false;
+  };
+  auto are_equal = [&is_less_than](const OrderedItem& a, const OrderedItem& b) {
+    return !is_less_than(a, b) && !is_less_than(b, a);
   };
 
   // We emit IR items in the order of the decls they were generated for.
   // For decls that emit multiple items we use a stable, but arbitrary order.
   std::vector<OrderedItem> items;
   for (const auto& [decl, result] : lookup_cache_) {
-    int local_order;
-
-    if (clang::isa<clang::RecordDecl>(decl)) {
-      local_order = decl->getDeclContext()->isRecord() ? 1 : 0;
-    } else if (auto ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
-      local_order = ctor->isDefaultConstructor() ? 2
-                    : ctor->isCopyConstructor()  ? 3
-                    : ctor->isMoveConstructor()  ? 4
-                                                 : 5;
-    } else if (clang::isa<clang::CXXDestructorDecl>(decl)) {
-      local_order = 6;
-    } else {
-      local_order = 7;
-    }
-
     auto item = result.item();
     if (item) {
       items.push_back(
-          std::make_tuple(decl->getSourceRange(), local_order, *item));
+          std::make_tuple(decl->getSourceRange(), GetDeclOrder(decl), *item));
     }
     if (IsFromCurrentTarget(decl)) {
+      std::string name = "unnamed";
+      if (const auto* named_decl = clang::dyn_cast<clang::NamedDecl>(decl)) {
+        name = named_decl->getQualifiedNameAsString();
+      }
+      SourceLoc source_loc = ConvertSourceLocation(decl->getBeginLoc());
       for (const auto& error : result.errors()) {
-        std::string name = "unnamed";
-        if (const auto* named_decl = clang::dyn_cast<clang::NamedDecl>(decl)) {
-          name = named_decl->getQualifiedNameAsString();
-        }
         items.push_back(std::make_tuple(
-            decl->getSourceRange(), local_order,
+            decl->getSourceRange(), GetDeclOrder(decl),
             UnsupportedItem{
-                .name = std::move(name),
-                .message = error,
-                .source_loc = ConvertSourceLocation(decl->getBeginLoc())}));
+                .name = name, .message = error, .source_loc = source_loc}));
       }
     }
   }
 
   for (auto comment : ImportFreeComments()) {
     items.push_back(std::make_tuple(
-        comment->getSourceRange(), 0 /* local_order */,
+        comment->getSourceRange(), 0 /* decl_order */,
         Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics())}));
   }
-  std::stable_sort(items.begin(), items.end(), is_less_than);
+  std::sort(items.begin(), items.end(), is_less_than);
 
-  for (const auto& item : items) {
+  for (size_t i = 0; i < items.size(); i++) {
+    const auto& item = items[i];
+    if (i > 0) {
+      const auto& prev = items[i - 1];
+      if (are_equal(item, prev)) {
+        std::string prev_json =
+            std::visit([&](auto&& item) { return item.ToJson().dump(); },
+                       std::get<2>(prev));
+        std::string curr_json =
+            std::visit([&](auto&& item) { return item.ToJson().dump(); },
+                       std::get<2>(item));
+        if (prev_json != curr_json) {
+          LOG(FATAL) << "Non-deterministic order of IR items: " << prev_json
+                     << " -VS- " << curr_json;
+        } else {
+          // TODO(lukasza): Avoid generating duplicate IR items.  Currently
+          // known example: UnsupportedItem: name=std::signbit; message=
+          // Items contained in namespaces are not supported yet.
+          LOG(WARNING) << "Duplicated IR item: " << curr_json;
+          continue;
+        }
+      }
+    }
     invocation_.ir_.items.push_back(std::get<2>(item));
   }
 }
@@ -358,7 +417,13 @@
   llvm::DenseSet<devtools_rust::Lifetime> all_lifetimes;
 
   std::vector<FuncParam> params;
-  std::vector<std::string> errors;
+  std::set<std::string> errors;
+  auto add_error = [&errors, function_decl](std::string msg) {
+    auto result = errors.insert(std::move(msg));
+    CHECK(result.second) << "Duplicated error message for "
+                         << function_decl->getNameAsString() << ": "
+                         << *result.first;
+  };
   if (auto* method_decl =
           clang::dyn_cast<clang::CXXMethodDecl>(function_decl)) {
     if (!known_type_decls_.contains(
@@ -376,7 +441,8 @@
       auto param_type = ConvertType(method_decl->getThisType(), this_lifetimes,
                                     /*nullable=*/false);
       if (!param_type.ok()) {
-        errors.push_back(std::string(param_type.status().message()));
+        add_error(absl::StrCat("`this` parameter is not supported: ",
+                               param_type.status().message()));
       } else {
         params.push_back({*std::move(param_type), Identifier("__this")});
       }
@@ -395,8 +461,8 @@
     }
     auto param_type = ConvertType(param->getType(), param_lifetimes);
     if (!param_type.ok()) {
-      errors.push_back(absl::Substitute("Parameter type '$0' is not supported",
-                                        param->getType().getAsString()));
+      add_error(absl::Substitute("Parameter #$0 is not supported: $1", i,
+                                 param_type.status().message()));
       continue;
     }
 
@@ -408,10 +474,10 @@
         // have a different representation which needs special support. We
         // currently do not support it.
         if (!record_decl->canPassInRegisters()) {
-          errors.push_back(
+          add_error(
               absl::Substitute("Non-trivial_abi type '$0' is not "
-                               "supported by value as a parameter",
-                               param->getType().getAsString()));
+                               "supported by value as parameter #$1",
+                               param->getType().getAsString(), i));
         }
       }
     }
@@ -429,7 +495,7 @@
       // have a different representation which needs special support. We
       // currently do not support it.
       if (!record_decl->canPassInRegisters()) {
-        errors.push_back(
+        add_error(
             absl::Substitute("Non-trivial_abi type '$0' is not supported "
                              "by value as a return type",
                              function_decl->getReturnType().getAsString()));
@@ -445,9 +511,8 @@
   auto return_type =
       ConvertType(function_decl->getReturnType(), return_lifetimes);
   if (!return_type.ok()) {
-    errors.push_back(
-        absl::Substitute("Return type '$0' is not supported",
-                         function_decl->getReturnType().getAsString()));
+    add_error(absl::StrCat("Return type is not supported: ",
+                           return_type.status().message()));
   }
 
   std::vector<Lifetime> lifetime_params;
diff --git a/rs_bindings_from_cc/importer.h b/rs_bindings_from_cc/importer.h
index 87e8533..92fb058 100644
--- a/rs_bindings_from_cc/importer.h
+++ b/rs_bindings_from_cc/importer.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <optional>
+#include <set>
 #include <string>
 #include <utility>
 #include <variant>
@@ -95,16 +96,16 @@
   // don't get imported on purpose.
   class LookupResult {
     std::optional<IR::Item> item_;
-    std::vector<std::string> errors_;
+    std::set<std::string> errors_;
 
    public:
     LookupResult() {}
     explicit LookupResult(IR::Item item) : item_(item) {}
     explicit LookupResult(std::string error) : errors_({error}) {}
-    explicit LookupResult(std::vector<std::string> errors) : errors_(errors) {}
+    explicit LookupResult(std::set<std::string> errors) : errors_(errors) {}
 
     const std::optional<IR::Item>& item() const { return item_; }
-    const std::vector<std::string>& errors() const { return errors_; }
+    const std::set<std::string>& errors() const { return errors_; }
   };
 
   // Imports all decls contained in a `DeclContext`.
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index 79f4863..38f9e4f 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -2666,9 +2666,11 @@
             ir.functions().find(|f| f.name == UnqualifiedIdentifier::Destructor).unwrap();
         assert_eq!(thunk_ident(&destructor), make_rs_ident("__rust_thunk___ZN5ClassD1Ev"));
 
-        let constructor =
-            ir.functions().find(|f| f.name == UnqualifiedIdentifier::Constructor).unwrap();
-        assert_eq!(thunk_ident(&constructor), make_rs_ident("__rust_thunk___ZN5ClassC1Ev"));
+        let default_constructor = ir
+            .functions()
+            .find(|f| f.name == UnqualifiedIdentifier::Constructor && f.params.len() == 1)
+            .unwrap();
+        assert_eq!(thunk_ident(&default_constructor), make_rs_ident("__rust_thunk___ZN5ClassC1Ev"));
     }
 
     #[test]
diff --git a/rs_bindings_from_cc/test/golden/comment_rs_api.rs b/rs_bindings_from_cc/test/golden/comment_rs_api.rs
index 3336670..dc02fca 100644
--- a/rs_bindings_from_cc/test/golden/comment_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/comment_rs_api.rs
@@ -40,11 +40,11 @@
 
 // rs_bindings_from_cc/test/golden/comment.h;l=13
 // Error while generating bindings for item 'Foo::Foo':
-// Parameter type 'struct Foo &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Foo &&'
 
 // rs_bindings_from_cc/test/golden/comment.h;l=13
 // Error while generating bindings for item 'Foo::operator=':
-// Parameter type 'struct Foo &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Foo &&'
 
 // b
 
@@ -78,11 +78,11 @@
 
 // rs_bindings_from_cc/test/golden/comment.h;l=39
 // Error while generating bindings for item 'Bar::Bar':
-// Parameter type 'struct Bar &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Bar &&'
 
 // rs_bindings_from_cc/test/golden/comment.h;l=39
 // Error while generating bindings for item 'Bar::operator=':
-// Parameter type 'struct Bar &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Bar &&'
 
 /// d
 #[derive(Clone, Copy)]
@@ -104,11 +104,11 @@
 
 // rs_bindings_from_cc/test/golden/comment.h;l=45
 // Error while generating bindings for item 'HasNoComments::HasNoComments':
-// Parameter type 'struct HasNoComments &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct HasNoComments &&'
 
 // rs_bindings_from_cc/test/golden/comment.h;l=45
 // Error while generating bindings for item 'HasNoComments::operator=':
-// Parameter type 'struct HasNoComments &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct HasNoComments &&'
 
 // e
 
diff --git a/rs_bindings_from_cc/test/golden/doc_comment_rs_api.rs b/rs_bindings_from_cc/test/golden/doc_comment_rs_api.rs
index ad627d5..f55785a 100644
--- a/rs_bindings_from_cc/test/golden/doc_comment_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/doc_comment_rs_api.rs
@@ -23,11 +23,11 @@
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=9
 // Error while generating bindings for item 'DocCommentSlashes::DocCommentSlashes':
-// Parameter type 'struct DocCommentSlashes &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct DocCommentSlashes &&'
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=9
 // Error while generating bindings for item 'DocCommentSlashes::operator=':
-// Parameter type 'struct DocCommentSlashes &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct DocCommentSlashes &&'
 
 /// The default constructor which will get translated into
 /// `impl Default for DocCommentSlashes`.
@@ -104,11 +104,11 @@
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=35
 // Error while generating bindings for item 'DocCommentBang::DocCommentBang':
-// Parameter type 'struct DocCommentBang &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct DocCommentBang &&'
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=35
 // Error while generating bindings for item 'DocCommentBang::operator=':
-// Parameter type 'struct DocCommentBang &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct DocCommentBang &&'
 
 /// Multiline comment
 ///
@@ -133,11 +133,11 @@
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=43
 // Error while generating bindings for item 'MultilineCommentTwoStars::MultilineCommentTwoStars':
-// Parameter type 'struct MultilineCommentTwoStars &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct MultilineCommentTwoStars &&'
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=43
 // Error while generating bindings for item 'MultilineCommentTwoStars::operator=':
-// Parameter type 'struct MultilineCommentTwoStars &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct MultilineCommentTwoStars &&'
 
 /// Line comment
 ///
@@ -162,11 +162,11 @@
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=51
 // Error while generating bindings for item 'LineComment::LineComment':
-// Parameter type 'struct LineComment &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct LineComment &&'
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=51
 // Error while generating bindings for item 'LineComment::operator=':
-// Parameter type 'struct LineComment &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct LineComment &&'
 
 /// Multiline comment
 ///
@@ -191,11 +191,11 @@
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=59
 // Error while generating bindings for item 'MultilineOneStar::MultilineOneStar':
-// Parameter type 'struct MultilineOneStar &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct MultilineOneStar &&'
 
 // rs_bindings_from_cc/test/golden/doc_comment.h;l=59
 // Error while generating bindings for item 'MultilineOneStar::operator=':
-// Parameter type 'struct MultilineOneStar &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct MultilineOneStar &&'
 
 /// A function
 #[inline(always)]
diff --git a/rs_bindings_from_cc/test/golden/escaping_keywords_rs_api.rs b/rs_bindings_from_cc/test/golden/escaping_keywords_rs_api.rs
index 351d60c..23872be 100644
--- a/rs_bindings_from_cc/test/golden/escaping_keywords_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/escaping_keywords_rs_api.rs
@@ -30,11 +30,11 @@
 
 // rs_bindings_from_cc/test/golden/escaping_keywords.h;l=6
 // Error while generating bindings for item 'type::type':
-// Parameter type 'struct type &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct type &&'
 
 // rs_bindings_from_cc/test/golden/escaping_keywords.h;l=6
 // Error while generating bindings for item 'type::operator=':
-// Parameter type 'struct type &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct type &&'
 
 #[inline(always)]
 pub fn r#impl(r#match: i32) {
diff --git a/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs b/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
index 5e7f275..7358dcf 100644
--- a/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
@@ -24,11 +24,11 @@
 
 // rs_bindings_from_cc/test/golden/inheritance.h;l=9
 // Error while generating bindings for item 'Base0::Base0':
-// Parameter type 'class Base0 &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class Base0 &&'
 
 // rs_bindings_from_cc/test/golden/inheritance.h;l=9
 // Error while generating bindings for item 'Base0::operator=':
-// Parameter type 'class Base0 &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class Base0 &&'
 
 #[repr(C)]
 pub struct Base1 {
@@ -40,11 +40,11 @@
 
 // rs_bindings_from_cc/test/golden/inheritance.h;l=10
 // Error while generating bindings for item 'Base1::Base1':
-// Parameter type 'class Base1 &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class Base1 &&'
 
 // rs_bindings_from_cc/test/golden/inheritance.h;l=10
 // Error while generating bindings for item 'Base1::operator=':
-// Parameter type 'class Base1 &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class Base1 &&'
 
 #[repr(C)]
 pub struct Base2 {
@@ -55,11 +55,11 @@
 
 // rs_bindings_from_cc/test/golden/inheritance.h;l=15
 // Error while generating bindings for item 'Base2::Base2':
-// Parameter type 'class Base2 &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class Base2 &&'
 
 // rs_bindings_from_cc/test/golden/inheritance.h;l=15
 // Error while generating bindings for item 'Base2::operator=':
-// Parameter type 'class Base2 &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class Base2 &&'
 
 #[derive(Clone, Copy)]
 #[repr(C, align(8))]
@@ -85,11 +85,11 @@
 
 // rs_bindings_from_cc/test/golden/inheritance.h;l=19
 // Error while generating bindings for item 'Derived::Derived':
-// Parameter type 'struct Derived &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Derived &&'
 
 // rs_bindings_from_cc/test/golden/inheritance.h;l=19
 // Error while generating bindings for item 'Derived::operator=':
-// Parameter type 'struct Derived &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Derived &&'
 
 // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_INHERITANCE_H_
 
diff --git a/rs_bindings_from_cc/test/golden/item_order_rs_api.rs b/rs_bindings_from_cc/test/golden/item_order_rs_api.rs
index 4d430cc..4d59b5c 100644
--- a/rs_bindings_from_cc/test/golden/item_order_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/item_order_rs_api.rs
@@ -30,11 +30,11 @@
 
 // rs_bindings_from_cc/test/golden/item_order.h;l=6
 // Error while generating bindings for item 'FirstStruct::FirstStruct':
-// Parameter type 'struct FirstStruct &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct FirstStruct &&'
 
 // rs_bindings_from_cc/test/golden/item_order.h;l=6
 // Error while generating bindings for item 'FirstStruct::operator=':
-// Parameter type 'struct FirstStruct &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct FirstStruct &&'
 
 #[inline(always)]
 pub fn first_func() -> i32 {
@@ -60,11 +60,11 @@
 
 // rs_bindings_from_cc/test/golden/item_order.h;l=12
 // Error while generating bindings for item 'SecondStruct::SecondStruct':
-// Parameter type 'struct SecondStruct &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct SecondStruct &&'
 
 // rs_bindings_from_cc/test/golden/item_order.h;l=12
 // Error while generating bindings for item 'SecondStruct::operator=':
-// Parameter type 'struct SecondStruct &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct SecondStruct &&'
 
 #[inline(always)]
 pub fn second_func() -> i32 {
diff --git a/rs_bindings_from_cc/test/golden/lifetimes_rs_api.rs b/rs_bindings_from_cc/test/golden/lifetimes_rs_api.rs
index 8410622..419546e 100644
--- a/rs_bindings_from_cc/test/golden/lifetimes_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/lifetimes_rs_api.rs
@@ -11,7 +11,7 @@
 
 // rs_bindings_from_cc/test/golden/lifetimes.h;l=4
 // Error while generating bindings for item 'AddHook':
-// Parameter type 'void (*)(void)' is not supported
+// Parameter #0 is not supported: Unsupported type 'void (*)(void)'
 
 // rs_bindings_from_cc/test/golden/lifetimes.h;l=6
 // Error while generating bindings for item 'FunctionPointer':
@@ -19,11 +19,11 @@
 
 // rs_bindings_from_cc/test/golden/lifetimes.h;l=7
 // Error while generating bindings for item 'AddHookWithTypedef':
-// Parameter type 'FunctionPointer' is not supported
+// Parameter #0 is not supported: Unsupported type 'FunctionPointer'
 
 // rs_bindings_from_cc/test/golden/lifetimes.h;l=9
 // Error while generating bindings for item 'AddAnotherHook':
-// Parameter type 'void (&)(void)' is not supported
+// Parameter #0 is not supported: Unsupported type 'void (&)(void)'
 
 // rs_bindings_from_cc/test/golden/lifetimes.h;l=11
 // Error while generating bindings for item 'FunctionReference':
@@ -31,7 +31,7 @@
 
 // rs_bindings_from_cc/test/golden/lifetimes.h;l=12
 // Error while generating bindings for item 'AddAnotherHookWithTypedef':
-// Parameter type 'FunctionReference' is not supported
+// Parameter #0 is not supported: Unsupported type 'FunctionReference'
 
 #[inline(always)]
 pub unsafe fn ConsumeArray(pair: *mut i32) {
diff --git a/rs_bindings_from_cc/test/golden/no_elided_lifetimes_rs_api.rs b/rs_bindings_from_cc/test/golden/no_elided_lifetimes_rs_api.rs
index 9b10aed..7f10548 100644
--- a/rs_bindings_from_cc/test/golden/no_elided_lifetimes_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/no_elided_lifetimes_rs_api.rs
@@ -25,11 +25,11 @@
 
 // rs_bindings_from_cc/test/golden/no_elided_lifetimes.h;l=6
 // Error while generating bindings for item 'S::S':
-// Parameter type 'struct S &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct S &&'
 
 // rs_bindings_from_cc/test/golden/no_elided_lifetimes.h;l=6
 // Error while generating bindings for item 'S::operator=':
-// Parameter type 'struct S &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct S &&'
 
 impl S {
     #[inline(always)]
diff --git a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
index 5855184..cbda839 100644
--- a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
@@ -25,7 +25,7 @@
 
 // rs_bindings_from_cc/test/golden/nontrivial_type.h;l=12
 // Error while generating bindings for item 'Nontrivial::Nontrivial':
-// Parameter type 'struct Nontrivial &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Nontrivial &&'
 
 impl Drop for Nontrivial {
     #[inline(always)]
@@ -47,7 +47,7 @@
 
 // rs_bindings_from_cc/test/golden/nontrivial_type.h;l=23
 // Error while generating bindings for item 'NontrivialInline::NontrivialInline':
-// Parameter type 'struct NontrivialInline &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct NontrivialInline &&'
 
 impl Drop for NontrivialInline {
     #[inline(always)]
@@ -70,7 +70,7 @@
 
 // rs_bindings_from_cc/test/golden/nontrivial_type.h;l=34
 // Error while generating bindings for item 'NontrivialMembers::NontrivialMembers':
-// Parameter type 'struct NontrivialMembers &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct NontrivialMembers &&'
 
 impl Drop for NontrivialMembers {
     #[inline(always)]
@@ -81,11 +81,11 @@
 
 // rs_bindings_from_cc/test/golden/nontrivial_type.h;l=38
 // Error while generating bindings for item 'TakesByValue':
-// Non-trivial_abi type 'struct Nontrivial' is not supported by value as a parameter
+// Non-trivial_abi type 'struct Nontrivial' is not supported by value as parameter #0
 
 // rs_bindings_from_cc/test/golden/nontrivial_type.h;l=39
 // Error while generating bindings for item 'TakesByValueInline':
-// Non-trivial_abi type 'struct NontrivialInline' is not supported by value as a parameter
+// Non-trivial_abi type 'struct NontrivialInline' is not supported by value as parameter #0
 
 // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_NONTRIVIAL_TYPE_H_
 
diff --git a/rs_bindings_from_cc/test/golden/private_members_rs_api.rs b/rs_bindings_from_cc/test/golden/private_members_rs_api.rs
index 4500b60..558afd6 100644
--- a/rs_bindings_from_cc/test/golden/private_members_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/private_members_rs_api.rs
@@ -31,11 +31,11 @@
 
 // rs_bindings_from_cc/test/golden/private_members.h;l=6
 // Error while generating bindings for item 'SomeClass::SomeClass':
-// Parameter type 'class SomeClass &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class SomeClass &&'
 
 // rs_bindings_from_cc/test/golden/private_members.h;l=6
 // Error while generating bindings for item 'SomeClass::operator=':
-// Parameter type 'class SomeClass &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class SomeClass &&'
 
 impl SomeClass {
     #[inline(always)]
diff --git a/rs_bindings_from_cc/test/golden/static_methods_rs_api.rs b/rs_bindings_from_cc/test/golden/static_methods_rs_api.rs
index e258c1c..2d0c500 100644
--- a/rs_bindings_from_cc/test/golden/static_methods_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/static_methods_rs_api.rs
@@ -30,11 +30,11 @@
 
 // rs_bindings_from_cc/test/golden/static_methods.h;l=6
 // Error while generating bindings for item 'SomeClass::SomeClass':
-// Parameter type 'class SomeClass &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class SomeClass &&'
 
 // rs_bindings_from_cc/test/golden/static_methods.h;l=6
 // Error while generating bindings for item 'SomeClass::operator=':
-// Parameter type 'class SomeClass &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'class SomeClass &&'
 
 impl SomeClass {
     /// Example of a factory method.
diff --git a/rs_bindings_from_cc/test/golden/trivial_type_rs_api.rs b/rs_bindings_from_cc/test/golden/trivial_type_rs_api.rs
index e5e3303..b4e1fda 100644
--- a/rs_bindings_from_cc/test/golden/trivial_type_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/trivial_type_rs_api.rs
@@ -32,11 +32,11 @@
 
 // rs_bindings_from_cc/test/golden/trivial_type.h;l=8
 // Error while generating bindings for item 'Trivial::Trivial':
-// Parameter type 'struct Trivial &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Trivial &&'
 
 // rs_bindings_from_cc/test/golden/trivial_type.h;l=8
 // Error while generating bindings for item 'Trivial::operator=':
-// Parameter type 'struct Trivial &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Trivial &&'
 
 /// Defaulted special member functions are trivial on a struct with only trivial
 /// members.
@@ -59,11 +59,11 @@
 
 // rs_bindings_from_cc/test/golden/trivial_type.h;l=19
 // Error while generating bindings for item 'TrivialWithDefaulted::TrivialWithDefaulted':
-// Parameter type 'struct TrivialWithDefaulted &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct TrivialWithDefaulted &&'
 
 // rs_bindings_from_cc/test/golden/trivial_type.h;l=20
 // Error while generating bindings for item 'TrivialWithDefaulted::operator=':
-// Parameter type 'struct TrivialWithDefaulted &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct TrivialWithDefaulted &&'
 
 /// This struct is trivial, and therefore trivially relocatable etc., but still
 /// not safe to pass by reference as it is not final.
@@ -76,11 +76,11 @@
 
 // rs_bindings_from_cc/test/golden/trivial_type.h;l=29
 // Error while generating bindings for item 'TrivialNonfinal::TrivialNonfinal':
-// Parameter type 'struct TrivialNonfinal &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct TrivialNonfinal &&'
 
 // rs_bindings_from_cc/test/golden/trivial_type.h;l=29
 // Error while generating bindings for item 'TrivialNonfinal::operator=':
-// Parameter type 'struct TrivialNonfinal &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct TrivialNonfinal &&'
 
 #[inline(always)]
 pub fn TakesByValue(trivial: Trivial) {
diff --git a/rs_bindings_from_cc/test/golden/types_rs_api.rs b/rs_bindings_from_cc/test/golden/types_rs_api.rs
index 14445d0..8a04edc 100644
--- a/rs_bindings_from_cc/test/golden/types_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/types_rs_api.rs
@@ -31,11 +31,11 @@
 
 // rs_bindings_from_cc/test/golden/types.h;l=9
 // Error while generating bindings for item 'SomeStruct::SomeStruct':
-// Parameter type 'struct SomeStruct &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct SomeStruct &&'
 
 // rs_bindings_from_cc/test/golden/types.h;l=9
 // Error while generating bindings for item 'SomeStruct::operator=':
-// Parameter type 'struct SomeStruct &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct SomeStruct &&'
 
 // rs_bindings_from_cc/test/golden/types.h;l=11
 // Error while generating bindings for item 'SomeUnion':
@@ -99,7 +99,7 @@
 
 // rs_bindings_from_cc/test/golden/types.h;l=13
 // Error while generating bindings for item 'FieldTypeTestStruct::FieldTypeTestStruct':
-// Parameter type 'struct FieldTypeTestStruct &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct FieldTypeTestStruct &&'
 
 #[inline(always)]
 pub fn VoidReturningFunction() {
diff --git a/rs_bindings_from_cc/test/golden/unsupported.h b/rs_bindings_from_cc/test/golden/unsupported.h
index ccd8dac..fefc50a 100644
--- a/rs_bindings_from_cc/test/golden/unsupported.h
+++ b/rs_bindings_from_cc/test/golden/unsupported.h
@@ -16,7 +16,8 @@
 void UnsupportedParamType(NontrivialCustomType n);
 NontrivialCustomType UnsupportedReturnType();
 
-NontrivialCustomType MultipleReasons(NontrivialCustomType n, int);
+NontrivialCustomType MultipleReasons(NontrivialCustomType n, int,
+                                     NontrivialCustomType n2);
 
 namespace ns {
 void FunctionInNamespace();
diff --git a/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs b/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
index e6d3401..37d5228 100644
--- a/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
@@ -20,11 +20,11 @@
 
 // rs_bindings_from_cc/test/golden/unsupported.h;l=7
 // Error while generating bindings for item 'NontrivialCustomType::NontrivialCustomType':
-// Parameter type 'struct NontrivialCustomType &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct NontrivialCustomType &&'
 
 // rs_bindings_from_cc/test/golden/unsupported.h;l=12
 // Error while generating bindings for item 'UnsupportedParamType':
-// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a parameter
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as parameter #0
 
 // rs_bindings_from_cc/test/golden/unsupported.h;l=13
 // Error while generating bindings for item 'UnsupportedReturnType':
@@ -32,17 +32,21 @@
 
 // rs_bindings_from_cc/test/golden/unsupported.h;l=15
 // Error while generating bindings for item 'MultipleReasons':
-// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a parameter
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a return type
 
 // rs_bindings_from_cc/test/golden/unsupported.h;l=15
 // Error while generating bindings for item 'MultipleReasons':
-// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a return type
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as parameter #0
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=18
+// rs_bindings_from_cc/test/golden/unsupported.h;l=15
+// Error while generating bindings for item 'MultipleReasons':
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as parameter #2
+
+// rs_bindings_from_cc/test/golden/unsupported.h;l=19
 // Error while generating bindings for item 'ns::FunctionInNamespace':
 // Items contained in namespaces are not supported yet
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=19
+// rs_bindings_from_cc/test/golden/unsupported.h;l=20
 // Error while generating bindings for item 'ns::StructInNamespace':
 // Items contained in namespaces are not supported yet
 
@@ -66,23 +70,23 @@
     }
 }
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=25
+// rs_bindings_from_cc/test/golden/unsupported.h;l=26
 // Error while generating bindings for item 'ContainingStruct::ContainingStruct':
-// Parameter type 'struct ContainingStruct &&' is not supported
-
-// rs_bindings_from_cc/test/golden/unsupported.h;l=25
-// Error while generating bindings for item 'ContainingStruct::operator=':
-// Parameter type 'struct ContainingStruct &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct ContainingStruct &&'
 
 // rs_bindings_from_cc/test/golden/unsupported.h;l=26
+// Error while generating bindings for item 'ContainingStruct::operator=':
+// Parameter #0 is not supported: Unsupported type 'struct ContainingStruct &&'
+
+// rs_bindings_from_cc/test/golden/unsupported.h;l=27
 // Error while generating bindings for item 'ContainingStruct::NestedStruct':
 // Nested classes are not supported yet
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=27
+// rs_bindings_from_cc/test/golden/unsupported.h;l=28
 // Error while generating bindings for item 'ContainingStruct::NestedStruct::NonStaticMemberFunction':
 // Couldn't import the parent
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=28
+// rs_bindings_from_cc/test/golden/unsupported.h;l=29
 // Error while generating bindings for item 'ContainingStruct::NestedStruct::StaticMemberFunction':
 // Couldn't import the parent
 
diff --git a/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs b/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
index 6c71774..28241d1 100644
--- a/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
@@ -40,11 +40,11 @@
 
 // rs_bindings_from_cc/test/golden/user_of_base_class.h;l=11
 // Error while generating bindings for item 'Derived2::Derived2':
-// Parameter type 'struct Derived2 &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Derived2 &&'
 
 // rs_bindings_from_cc/test/golden/user_of_base_class.h;l=11
 // Error while generating bindings for item 'Derived2::operator=':
-// Parameter type 'struct Derived2 &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct Derived2 &&'
 
 // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_USER_OF_BASE_CLASS_H_
 
diff --git a/rs_bindings_from_cc/test/golden/user_of_imported_type_rs_api.rs b/rs_bindings_from_cc/test/golden/user_of_imported_type_rs_api.rs
index 3bf22f0..7ee1c32 100644
--- a/rs_bindings_from_cc/test/golden/user_of_imported_type_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/user_of_imported_type_rs_api.rs
@@ -35,11 +35,11 @@
 
 // rs_bindings_from_cc/test/golden/user_of_imported_type.h;l=10
 // Error while generating bindings for item 'UserOfImportedType::UserOfImportedType':
-// Parameter type 'struct UserOfImportedType &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct UserOfImportedType &&'
 
 // rs_bindings_from_cc/test/golden/user_of_imported_type.h;l=10
 // Error while generating bindings for item 'UserOfImportedType::operator=':
-// Parameter type 'struct UserOfImportedType &&' is not supported
+// Parameter #0 is not supported: Unsupported type 'struct UserOfImportedType &&'
 
 // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_USER_OF_IMPORTED_TYPE_H_
 
diff --git a/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs b/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs
index b87f48d..1afda56 100644
--- a/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs
@@ -11,11 +11,11 @@
 
 // rs_bindings_from_cc/test/golden/user_of_unsupported.h;l=8
 // Error while generating bindings for item 'UseNontrivialCustomType':
-// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a parameter
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as parameter #0
 
 // rs_bindings_from_cc/test/golden/user_of_unsupported.h;l=10
 // Error while generating bindings for item 'UseUnsupportedType':
-// Parameter type 'ns::StructInNamespace *' is not supported
+// Parameter #0 is not supported: Unsupported type 'ns::StructInNamespace *'
 
 // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_USER_OF_UNSUPPORTED_H_