Top 14 leaders Toulouse produced a magnificent display as they overcame the first-half dismissal of Zack Holmes to claim a dramatic 22-21 victory over Racing 92 and reach the European Champions Cup semi-finals.

Fly-half Holmes was sent off after just 23 minutes of a thrilling contest for a dangerous tackle on Juan Imhoff, which saw him forcefully - albeit seemingly inadvertently - strike the wing in the neck with his right shoulder.

Toulouse trailed by three points at the time, but turned on the style to go into the interval with a 19-10 lead as Maxime Medard finished one spectacular move and a glorious counter-attack from deep - with Racing temporarily down to 14 after a yellow card for Teddy Thomas - laid the platform for Antoine Dupont's second try.

Racing, beaten finalists in 2016 and 2018, piled on the pressure after the interval and reduced their deficit to a single point courtesy of a 74th-minute try from substitute hooker Camille Chat.

However, Maxime Machenaud could not convert from the touchline and Toulouse, whose only second-half points came from the boot of Thomas Ramos after Imhoff had been sin-binned, held on to claim a famous win and book a semi-final meeting with reigning champions Leinster.

Racing thought they had claimed a match-winning score with two minutes remaining, but it was chalked off after Leone Nakarawa was adjudged to have made illegal contact with Richie Arnold at a lineout before dotting down.

Toulouse's attacking flair was in evidence early on as Cheslin Kolbe and Medard switched play inside to put Dupont through a gap, with Holmes converting the game's opening try.

After Machenaud had kicked his first three-pointer, Racing's Finn Russell provided a moment to savour, intercepting a pass from opposite number Holmes before producing a perfectly weighted grubber kick that left the rapid Thomas with an easy finish.

With Racing 10-7 to the good following Machenaud's touchline conversion, the dismissal of Holmes left Toulouse with a mountain to climb.

Yet a wonderful offload from the impressive Lucas Tauzin – a late replacement for Yoann Huget in the Toulouse starting XV – and the dancing feet of Sofiane Guitoune set up a Medard try, before a dazzling, length-of-the-field break earned a five-metre scrum, from which Dupont scampered over.

Two Machenaud penalties in the second period made it 19-16, before Toulouse countered with style once again and Imhoff was yellow-carded for illegally slowing things down, with Ramos landing the resulting three-pointer.

Chat capitalised on a Kolbe error to give Machenaud the chance to be Racing's hero, but the scrum-half missed from the touchline and Nakarawa's lineout infringement meant the lock's late try was disallowed.