Since the inlining is performed in MSVC's backend, as opposed to its frontend, and hence operates strictly on MSVC's intermediate representation which lacks information about tokens or the AST, it's unlikely due to tokens.
std::exception does not take a string in its constructor, so most likely you used std::runtime_error. std::runtime_error has a pretty complex constructor if you pass into it a long string. If it's a small string then there's no issue because it stores its contents in an internal buffer, but if it's a longer string then it has to use a reference counting scheme to allow for its copy constructor to be noexcept.
That is why you can see different behavior if you use a long string versus a short string. You can also see vastly different codegen with plain std::string as well depending on whether you pass it a short string literal or a long string literal.
> std::exception does not take a string in its constructor
You're right, I used it as a short-hand for our internal exception function, forgetting that the std one does not take a string.
Our error handling function is a simple static function that takes an std::string and throws a newly constructed object with that string as a field.
But yes, it could very well have been that the string surpassed the short string optimisation threshold or something similar.
I did verify the assembly before and after and the function definitely inlined before and no longer inlined after. Moving the 'throw' (and, importantly, the string literal) into a separate function that was called from the same spot ensured it inlined again and the performance was back to normal.
std::exception does not take a string in its constructor, so most likely you used std::runtime_error. std::runtime_error has a pretty complex constructor if you pass into it a long string. If it's a small string then there's no issue because it stores its contents in an internal buffer, but if it's a longer string then it has to use a reference counting scheme to allow for its copy constructor to be noexcept.
That is why you can see different behavior if you use a long string versus a short string. You can also see vastly different codegen with plain std::string as well depending on whether you pass it a short string literal or a long string literal.