Lost a whole evening to this one last month, so here it is in case it saves someone else the pain. I had a pushbutton on PB15 configured as plain input with the internal pull-up, and it read low constantly no matter what. Swapped buttons, checked continuity, even tried a different board. Nothing. The catch with the G0 series is that some pins get a pull-down enabled right out of reset depending on the state of their neighbouring pins, and PB15 is one of them. It's part of the USB Type-C dead battery support, which is completely irrelevant if you're not using USB, but the hardware doesn't care. So your nice pull-up gets fought by a hidden pull-down and the pin just sits low.
The fix is one line in your init before you touch GPIO clocks. Turn on the SYSCFG clock, then set the UCPD1 strobe bit in SYSCFG_CFGR1. That releases the hidden pull-down and PB15 suddenly behaves like a normal input. Set your pull-up after that and you're done. Worth reading the errata or the reference manual section on SYSCFG if you're on this family, because PA8, PD0 and PD2 can have the same issue. It's the kind of thing you only find after an hour of doubting your own soldering.