[Tex/LaTex] ! Corrupted NFSS tables

font-encodingslatex-base

Update

The LaTeX-bug described in this question has been resolved. With the new LaTeX in TeXlive 2015 (tested on 2015-05-14) there is no longer an error.

Original Question

The following code gives the error ! Corrupted NFSS tables..

Can someone explain why exactly and what should be done to avoid it?

In the real document the error was triggered by a \normalfont in a font package and a \selectlanguage{vietnam} in the aux-file (so simply moving the lines in the preamble is not really a solution).

\documentclass{book}

\usepackage[T5,T1]{fontenc}
\renewcommand\rmdefault{fve}%no T5fve.fd

\fontencoding{T1}\fontfamily{\familydefault}\selectfont
\fontencoding{T5}\selectfont

\selectfont %error


\begin{document}
blub
\end{document}

Edit

After some digging I understand a bit more. One gets the error only in the preamble as at \begin{document} the command \process@table loads various default font definitions. One can avoid the error by loading t5cmr.fd early enough. But now I wonder who could ensure that it is done. The font package can't know that perhaps T5 encoding is wanted, babel can't know the \DefaultSubstituationFont.

Edit 2

I found a work-around to force latex to load the fd-file a bit earlier and so to setup the fallback font. I'm not quite sure if this as no side effects and I forwarded the question to the latex list.

\documentclass{book}

\usepackage[T5,T1]{fontenc}

\makeatletter
\def\wrong@fontshape{%
    \csname D@\f@encoding\endcsname      % install defaults if in math
    \edef\reserved@a{\csname\curr@fontshape\endcsname}%
  \ifx\last@fontshape\reserved@a
     \errmessage{Corrupted NFSS tables}%
     \error@fontshape
  \else
    \let\f@shape\default@shape
    \expandafter\ifx\csname\curr@fontshape\endcsname\relax
       \let\f@series\default@series
        \expandafter
          \ifx\csname\curr@fontshape\endcsname\relax
           \let\f@family\default@family
        \fi \fi
  \fi
     \@font@warning{Font shape `\expandafter\string\reserved@a'
                     \expandafter\@gobble\string\@undefined\MessageBreak
                   using `\curr@fontshape' instead\@wrong@font@char}%
   \begingroup\try@load@fontshape\endgroup  %<--------------new              
    \global\let\last@fontshape\reserved@a
    \gdef\@defaultsubs{%
      \@font@warning{Some font shapes were not available, defaults
                      substituted.\@gobbletwo}}%
    \global\expandafter\expandafter\expandafter\let
       \expandafter\reserved@a
           \csname\curr@fontshape\endcsname
    \xdef\font@name{%
      \csname\curr@fontshape/\f@size\endcsname}%
    \pickup@font}
\makeatother    

\renewcommand\rmdefault{fve}%no T5fve.fd

\fontencoding{T1}\fontfamily{\familydefault}\selectfont

\fontencoding{T5}\selectfont

\selectfont %error

\begin{document}
blub
\end{document}

Best Answer

An NFSS question ... how nice :-)

Looks like a quarter of century old deficiency. One could argue whether or not this is a bug or whether it is really due to the fact that in the preamble typesetting is not quite supported — I guess in the end it is a bit of both as NFSS sets up its final tables only at begin document. However, I tried to accommodate for font selection before that, but obviously missed one case.

What happens?

In NFSS the csname \<encoding>/<family>/<series>/<shape> holds a recipe how to get to the right font given a specific size, e.g., if \T5/fve/m/n/10 is being looked for, then \T5/fve/m/n will tell us how to get the font for size 10. If this macro is undefined then this is either because NFSS doesn't know about this or it hasn't loaded any definition for this family.

In the latter case it tries to find those definitions by loading a file named t5fve.fd hoping that this contains the right definitions. If after that it still hasn't got a definition it will change first the shape then the series and finally the family to some defaults in the hope to find some suitable alternative.

In the example \T5/fve/m/n/10 is requested at the first \selectfont: it doesn't exist and neither does the file t5fve.fd. So NFSS applies the defaults up to and including changing the family to cmr. Now that actually exists technically, but the corresponding t5cmr.fd has not been loaded yet.

Thus \T5/cmr/m/n does not yet have a definition when \wrong@fontshape executes and so the part near the end

\global\expandafter\expandafter\expandafter\let
   \expandafter\reserved@a
       \csname\curr@fontshape\endcsname

that equates the original request for \T5/fve/m/n (stored in \reserved@a) with the final substitute \T5/cmr/m/n just doesn't work as it defines \T5/fve/m/n to be \relax rather than something like

T5/fve/m/n=macro:
-><-5.5>vnr5<5.5-6.5>vnr6<6.5-7.5>vnr7<7.5-8.5>vnr8<8.5-9.5>vnr9<9.5-11>vnr10<1
1-15>vnr12<15->vnr17 

As a result the next \selectfont tries again to find \T5/fve/m/n/10 (instead of simply selecting what was found before) calling again on \wrong@fontshape. This time however \wrong@fontshape notices that it was tried before with exactly the same request and concludes that the NFSS tables are corrupted.

So Ulrike's second edit is correct: after doing the substitution, we should try to load any missing NFSS definitions from an external .fd file.

The position is not quite correct as this only makes sense if we have changed the family as NFSS definitions are stored per encoding/family, otherwise there is nothing "new" to load and the definition is either already in memory or doesn't exist.

So a correct (fingers crossed :-) change would be

\def\wrong@fontshape{%
    \csname D@\f@encoding\endcsname      % install defaults if in math
    \edef\reserved@a{\csname\curr@fontshape\endcsname}%
  \ifx\last@fontshape\reserved@a
     \errmessage{Corrupted NFSS tables}%
     \error@fontshape
  \else
    \let\f@shape\default@shape
    \expandafter\ifx\csname\curr@fontshape\endcsname\relax
       \let\f@series\default@series
        \expandafter
          \ifx\csname\curr@fontshape\endcsname\relax
           \let\f@family\default@family
           \begingroup\try@load@fontshape\endgroup  %<--------------new    
        \fi \fi
  \fi
     \@font@warning{Font shape `\expandafter\string\reserved@a'
                     \expandafter\@gobble\string\@undefined\MessageBreak
                   using `\curr@fontshape' instead\@wrong@font@char}%
    \global\let\last@fontshape\reserved@a
    \gdef\@defaultsubs{%
      \@font@warning{Some font shapes were not available, defaults
                      substituted.\@gobbletwo}}%
    \global\expandafter\expandafter\expandafter\let
       \expandafter\reserved@a
           \csname\curr@fontshape\endcsname
    \xdef\font@name{%
      \csname\curr@fontshape/\f@size\endcsname}%
    \pickup@font}

By the way: why is this only an issue in the preamble? Because all the defaults for each encoding are verified at begin document and any missing .fd file is loaded then. So inside the document everything has worked just fine, which is probably why nobody ever came across that in 25 years.

Update

A cleaned up version of the above code has been added to the new LaTeX kernel code so that the fix will be generally available when the TeX Live 2015 distribution will become generally available.

Related Question