\iffalse
followup: here is what i would propose except that either one also has to do
this to \@dbflt or put the \@currentlabel definition into \@xfloat or perhaps
\@floatboxreset --- which of these is best really depends on how other
packages hook into the kernel float mechanism
frank
\fi
\documentclass{article}
\makeatletter
\def\@float#1{%
\def\@currentlabel{\textbf{[bad label]}\protect\before@caption@err}%
%% or perhaps only: ?
\@ifnextchar[%
{\@xfloat{#1}}%
{\edef\reserved@a{\noexpand\@xfloat{#1}[\csname fps@#1\endcsname]}%
\reserved@a}}
\def\before@caption@err{\@latexerr{\noexpand\ref to misplaced
\string\label}%
{Labels have to follow the object that they are labeling. The
label you\MessageBreak are
referencing here should be moved after the
\noexpand\caption command.}}%
\makeatother
\begin{document}
\begin{figure} \label{foo} \end{figure}
Hallo \ref{foo} on page \pageref{foo}.
\end{document}