diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 1ebb82ffadcec5cf91141c4157109add5426fb4d..f3bfcc314402a2454bad5f497bdd992404b477d3 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -1449,6 +1449,11 @@ bool Moc::until(Token target) {
             --index;
             break;
         }
+
+        if (braceCount <= 0 && t == SEMIC) {
+            // Abort on semicolon. Allow recovering bad template parsing (QTBUG-31218)
+            break;
+        }
     }
 
     if(target == COMMA && angleCount != 0 && possible != -1) {
diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp
index e0179b393b3f6be0a84ed9387a9a673e9ed4225b..923275d92840e62d45fd9af6f4b85d3366216580 100644
--- a/tests/auto/tools/moc/tst_moc.cpp
+++ b/tests/auto/tools/moc/tst_moc.cpp
@@ -79,6 +79,9 @@
 
 QT_USE_NAMESPACE
 
+template <bool b> struct QTBUG_31218 {};
+struct QTBUG_31218_Derived : QTBUG_31218<-1<0> {};
+
 struct MyStruct {};
 struct MyStruct2 {};