"Allows more operations" seems like a straightforward meaning for "different semantics" to me. In Safe Rust, you can't access union members. In Unsafe Rust you can.
I agree that it's a little fanciful, but I also don't think it's really wrong.
> To suggest that this means that the language itself has infinite sublanguages obscures its actual sublanguages, such as the built-in macro-rules DSL.
In many languages, the macro language is either homoiconic or nearly homoiconic. In Crystal, for example, the macro DSL looks like normal Crystal, but with a few extra sigils. You can't invent new syntax in it.
When we talk about understanding C we generally take that to include the C preprocessor, despite the latter being a conceptually separate macro language. I think the same standard (except much, much better) applies to procedural macros in Rust: you need to understand a separate set of token production and consumption rules that interact but do not align with Rust's core syntax.
> This is a misunderstanding of the reference manual
I wasn't referring to the production rules themselves; I'm aware they're on most pages. I was referring to the fact that the attribute language is explicitly taken directly from a separate language (C#).
The semantics are the same. The meaning of the operation is same. In both safe and unsafe accessing union members is the same operation with the same meaning. The only difference is that in unsafe Rust you are allowed do this. This is a difference in permission, not meaning
Unsafe Rust doesn't have different semantics from Safe Rust, it's the exact same language but it allows more operations. Which is to say, for any given expression that compiles with Safe Rust, if you wrap that expression in an unsafe block it will have precisely the same semantics. For the book to describe it as a "second, hidden language" is being a bit fanciful on its part; it later goes on to clarify that it just gives you a handful of extra powers.
> Procedural macros can be used to define new languages within Rust
Sure, but by that logic, Rust (and every other language that supports DSLs) has infinite languages inside of it, which does not amount to a particularly useful distinction; either a language supports crafting DSLs or it doesn't. To suggest that this means that the language itself has infinite sublanguages obscures its actual sublanguages, such as the built-in macro-rules DSL.
> Attributes are the counterpart to Unsafe Rust: their syntax is described separately from the rest of Rust
This is a misunderstanding of the reference manual (which is itself non-normative and fairly ad-hoc in structure); most pages contain their own grammar specification, e.g. the syntax for items is described at https://doc.rust-lang.org/reference/items.html , but there is no user-facing item sublanguage in the same way that there is no user-facing attribute sublanguage. Attributes are attributes, they're just a part of Rust.