c++visual-c++c++17visual-c++-2019

Weird C2143 error with two consecutive if constexpr in the same function


I am compiling the following code with c++17:

#include <iostream>

struct A {
    void barA() const {std::cout << "barA\n";}
};

struct B {
    void barB() const {std::cout << "barB\n";}
};

template<typename T>
constexpr bool isBaseA() {
    return std::is_base_of<A, T>::value;
}

template<typename T>
constexpr bool isBaseB() {
    return std::is_base_of<B, T>::value;
}

template<typename... Args>
class K : public Args... {
public:
void foo() {
    using MyK = K<Args...>;
    
    if constexpr(isBaseA<MyK>()) {
        using X = typename MyK::A;
        X::barA();
    }
    if constexpr(isBaseB<MyK>()) {
        using X = typename MyK::B;
        X::barB();
    }
}
};

int main()
{
    K<A, B> k;
    k.foo();
    return 0;
}

Demo

When building with MSVC 2019 (version 16.8.30804.86, it should be the last available one), I am getting a weird C2143 error at the line

void foo() {

The complete C2143 error is :

<source>(24): error C2143: syntax error: missing ')' before ';'
<source>(24): note: while compiling class template member function 'void K<A,B>::foo(void)'
<source>(41): note: see reference to function template instantiation 'void K<A,B>::foo(void)' being compiled
<source>(40): note: see reference to class template instantiation 'K<A,B>' being compiled
<source>(24): error C2143: syntax error: missing ';' before ')'
<source>(24): error C2059: syntax error: ')'

I noticed that:

The code works fine both on gcc and clang. Is this just a MSVC bug, or am I breaking the c++17 standard somewhere in the code?


Solution

  • Looks like a parser bug, as adding parentheses avoids the error. Adding parentheses should have no effect at all in this context:

    template<typename... Args>
    class K : public Args... {
    public:
    void foo() {
        using MyK = K<Args...>;
        
        // extra parentheses to overcome MSVC error
        if constexpr((isBaseA<MyK>())) {
            using X = typename MyK::A;
            X::barA();
        }
        if constexpr(isBaseB<MyK>()) {
            using X = typename MyK::B;
            X::barB();
        }
    }
    };
    

    compiler explorer working example