\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}