diff --git a/gcc/rust/checks/errors/feature/rust-feature-collector.cc b/gcc/rust/checks/errors/feature/rust-feature-collector.cc
index 6a3a14792..bd5a910d9 100644
--- a/gcc/rust/checks/errors/feature/rust-feature-collector.cc
+++ b/gcc/rust/checks/errors/feature/rust-feature-collector.cc
@@ -18,6 +18,7 @@
 
 #include "rust-feature-collector.h"
 #include "rust-attribute-values.h"
+#include "rust-session-manager.h"
 
 namespace Rust {
 namespace Features {
@@ -32,6 +33,11 @@ FeatureCollector::collect (AST::Crate &crate)
   features.valid_lib_features.clear ();
   features.crate_id = crate.get_node_id ();
 
+  // TODO: this is a hack, remove when possible
+  if (Session::get_instance ().get_compat_version () < 50)
+    features.valid_lang_features.insert (
+      Feature::Name::EXTENDED_KEY_VALUE_ATTRIBUTES);
+
   visit (crate);
 
   return features;
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index c06290cdf..2ab9d2541 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -29,6 +29,7 @@
 #include "rust-cfg-strip.h"
 #include "rust-proc-macro.h"
 #include "rust-token-tree-desugar.h"
+#include "rust-session-manager.h"
 
 namespace Rust {
 
@@ -311,7 +312,7 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
   // We special case the `offset_of!()` macro if the flag is here and manually
   // resolve to the builtin transcriber we have specified
   auto assume_builtin_offset_of
-    = flag_assume_builtin_offset_of
+    = Session::get_instance ().should_support_offset_of ()
       && (invoc.get_invoc_data ().get_path ().as_string () == "offset_of")
       && !rules_def;
 
diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt
index 1d38fec86..f996ec0f0 100644
--- a/gcc/rust/lang.opt
+++ b/gcc/rust/lang.opt
@@ -229,9 +229,9 @@ frust-overflow-checks
 Rust Var(flag_overflow_checks) Init(1)
 Enable the overflow checks in code generation.
 
-frust-assume-builtin-offset-of
-Rust Var(flag_assume_builtin_offset_of)
-Define a built-in offset_of macro in the compiler and assume it is present.
+frust-compat-version=
+Rust Joined RejectNegative Var(flag_rust_compat_version)
+Select a version of rust to target for compatibility. Must be of form '1.x' or 'max'.
 
 frust-unused-check-2.0
 Rust Var(flag_unused_check_2_0)
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
index 0c5422d2c..854102ff9 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -30,6 +30,7 @@
 #include "rust-finalize-imports-2.0.h"
 #include "rust-attribute-values.h"
 #include "rust-identifier-path.h"
+#include "rust-session-manager.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -318,8 +319,8 @@ Early::visit (AST::MacroInvocation &invoc)
 
   // We special case the `offset_of!()` macro if the flag is here, otherwise
   // we accept whatever `offset_of!()` definition we resolved to.
-  auto resolve_offset_of
-    = flag_assume_builtin_offset_of && (path.as_string () == "offset_of");
+  auto resolve_offset_of = Session::get_instance ().should_support_offset_of ()
+			   && (path.as_string () == "offset_of");
 
   if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
     for (auto &pending_invoc : invoc.get_pending_eager_invocations ())
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 011ca8b99..6a56c956d 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -289,6 +289,9 @@ Session::handle_option (
     case OPT_frust_edition_:
       options.set_edition (flag_rust_edition);
       break;
+    case OPT_frust_compat_version_:
+      options.set_compat_version (flag_rust_compat_version);
+      break;
     case OPT_frust_compile_until_:
       options.set_compile_step (flag_rust_compile_until);
       break;
diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h
index 930012a7b..af5a700b8 100644
--- a/gcc/rust/rust-session-manager.h
+++ b/gcc/rust/rust-session-manager.h
@@ -242,6 +242,8 @@ struct CompileOptions
   bool debug_assertions = false;
   std::string metadata_output_path;
 
+  int compat_version = 49;
+
   /** Structure containing additional attributes to be injected within the
    * compiled crate from the command line instead of the source code.
    *
@@ -344,6 +346,30 @@ struct CompileOptions
 
   const Edition &get_edition () const { return edition; }
 
+  void set_compat_version (const char *version)
+  {
+    if (!strcmp (version, "max"))
+      {
+	compat_version = INT_MAX;
+	return;
+      }
+
+    long res;
+    char *end_ptr;
+    if (version[0] != '1' || version[1] != '.' || version[2] == '\0'
+	|| (res = strtol (version + 2, &end_ptr, 10), *end_ptr) || res < 0
+	|| res > INT_MAX)
+      {
+	rust_error_at (UNKNOWN_LOCATION,
+		       "compat version must be of form 1.x or be \"max\"");
+	return;
+      }
+
+    compat_version = res;
+  }
+
+  int get_compat_version () const { return compat_version; }
+
   void set_crate_type (int raw_type) { target_data.set_crate_type (raw_type); }
 
   bool is_proc_macro () const
@@ -474,6 +500,10 @@ public:
   tl::expected<LoadedCrate, LoadingError>
   load_extern_crate (const std::string &crate_name, location_t locus);
 
+  int get_compat_version () const { return options.get_compat_version (); }
+
+  bool should_support_offset_of () const { return get_compat_version () >= 71; }
+
 private:
   Session () : mappings (Analysis::Mappings::get ()) {}
   void compile_crate (const char *filename);
diff --git a/gcc/testsuite/rust/compile/early_feature_gate_in_macro.rs b/gcc/testsuite/rust/compile/early_feature_gate_in_macro.rs
index 9e2a51027..dd68b920e 100644
--- a/gcc/testsuite/rust/compile/early_feature_gate_in_macro.rs
+++ b/gcc/testsuite/rust/compile/early_feature_gate_in_macro.rs
@@ -1,3 +1,4 @@
+// { dg-additional-options "-frust-compat-version=1.50" }
 #![feature(rustc_attrs)]
 #![feature(lang_items)]
 #![feature(no_core)]
diff --git a/gcc/testsuite/rust/compile/offset_of1.rs b/gcc/testsuite/rust/compile/offset_of1.rs
index 2fca6d5ee..ff1bd4a21 100644
--- a/gcc/testsuite/rust/compile/offset_of1.rs
+++ b/gcc/testsuite/rust/compile/offset_of1.rs
@@ -1,4 +1,4 @@
-// { dg-additional-options "-frust-compile-until=lowering -frust-assume-builtin-offset-of" }
+// { dg-additional-options "-frust-compile-until=lowering -frust-compat-version=1.71" }
 #![feature(no_core)]
 #![no_core]
 
diff --git a/gcc/testsuite/rust/compile/offset_of2.rs b/gcc/testsuite/rust/compile/offset_of2.rs
index 2f2fa00a3..143aab1e0 100644
--- a/gcc/testsuite/rust/compile/offset_of2.rs
+++ b/gcc/testsuite/rust/compile/offset_of2.rs
@@ -1,4 +1,4 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-assume-builtin-offset-of" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-compat-version=1.71" }
 #![feature(no_core)]
 #![no_core]
 
diff --git a/gcc/testsuite/rust/compile/parse_time_feature_gate.rs b/gcc/testsuite/rust/compile/parse_time_feature_gate.rs
index 907ac0c51..1affcd81a 100644
--- a/gcc/testsuite/rust/compile/parse_time_feature_gate.rs
+++ b/gcc/testsuite/rust/compile/parse_time_feature_gate.rs
@@ -1,3 +1,4 @@
+// { dg-additional-options "-frust-compat-version=1.50" }
 #![feature(no_core)]
 #![no_core]
 #![feature(rustc_attrs)]
diff --git a/gcc/testsuite/rust/execute/torture/offset_of1.rs b/gcc/testsuite/rust/execute/torture/offset_of1.rs
index d8ab9eba4..9d17b2bb2 100644
--- a/gcc/testsuite/rust/execute/torture/offset_of1.rs
+++ b/gcc/testsuite/rust/execute/torture/offset_of1.rs
@@ -1,5 +1,5 @@
 // { dg-do run { target x86_64*-*-* } }
-// { dg-additional-options "-frust-assume-builtin-offset-of" }
+// { dg-additional-options "-frust-compat-version=1.71" }
 #![feature(no_core)]
 #![no_core]
 
