Skip to content
This repository has been archived by the owner on Feb 9, 2021. It is now read-only.

Repro case guide

Eric edited this page Sep 16, 2016 · 1 revision

What's A Repro?

  • A repro is self-contained, with all of the code necessary to demonstrate the issue. It's not a snippet. We shouldn't have to add any code, even #include directives for Standard headers. Complete and exact code is critical, because issues often depend on minor details.

  • We need your compiler version and target architecture as reported by running cl.exe with no arguments. We generally don't need additional information (e.g. OS version, host architecture), but feel free to provide it.

  • We need the exact command line being used to invoke the compiler. Issues sometimes depend on the precise compiler options being used.

  • We need to know the exact error message or exact runtime behavior that you're seeing, so we can verify that we've properly reproduced it. For an error message, we need all of the compiler's output, whether it's 1 line or 1000. (Note: the IDE and various build systems sometimes capture only the first line of an error in their filtered error logs. We want the whole thing, including any template instantiation context, as seen by invoking the compiler directly.) For runtime behavior, we need an exact copy of what the program's printing out, and a description of what you expect to see (ideally, embedded in the program itself, like printf("This should be 5: %d\n", x);). If it crashes or hangs, mention that (and it's useful to print out messages beforehand). If you have an accepts-invalid repro, where we should be emitting a compiler error but we aren't, then we just need to know what we should be rejecting.

What's A GOOD Repro?

  • A good repro is minimal, being as small and as simple as possible while still demonstrating the issue. We don't care what the code is doing or whether it's realistic, as long as it conforms to the Standard's rules (or our documentation, for VC-specific features). If you can eliminate or simplify something while remaining conformant and leaving the issue unchanged, please do so. Also, note that we don't care about code that works. Repros of the form "A, B, C, and D work perfectly, but E explodes" are unnecessary; a repro demonstrating "E explodes" is all that we need. If you really want to demonstrate how various changes affect the issue, you can do that, but please ensure that the repro demonstrates the issue without making any changes or defining any macros. (That is, you can include comments saying, "if I change this X to Y, it works", or "this explodes, but if you define WORKAROUND, this slightly different code works".)

  • Furthermore, good repros avoid unnecessary dependencies. For efficient investigations, this is worth much more than any other kind of simplification. If you can repro an issue without a third-party library, please do so. If you've encountered an issue with the STL, but it also repros if you use the CRT directly, please submit a CRT-only repro (that lets us rule out megabytes of code at a glance). If your issue looks like a compiler bug and you can reproduce it without any library code (except maybe print statements), please do so - that is enormously helpful. (This may be somewhat unintuitive because in everyday programming, you want to work at a high level of abstraction. But when investigating issues, we need to peel away the layers of abstraction until we find the relevant/defective one.)

  • Good repros use the latest compiler version. That's either the latest Update to the latest major version, or (if you're trying out our upcoming code) a pre-release build of our next Update, or a pre-release build of our next major version. If you report an issue with an older version, it's quite possible that it'll turn out to already have been fixed. Additionally, we backport fixes to older versions only in exceptional circumstances.

  • If your repro involves portable code, checking other compilers can be useful. Wandbox, unaffiliated with Microsoft, is an online compiler with the latest builds of Clang/libc++ and GCC/libstdc++. The Standard ultimately determines correctness and no compiler is perfect, but when Clang and GCC agree and VC disagrees, it's likely you're looking at a VC bug. (Other possibilities include Unix vs. Windows behavior, or varying levels of C++17 implementation, etc.) Conversely, if Clang/GCC/VC all agree, then it's likely that your code is incorrect, and seeing different error messages may help you diagnose the issue yourself.

Example: Library-Free Repro

This is the best way to report compiler bugs. Avoiding library code has two major benefits - we can send such repros directly to compiler devs, and they can easily debug into the compiler itself without having to watch it compile complicated library code.

C:\Temp>type meow.cpp
template <typename T1, typename T2> struct pair {
    T1 first;
    T2 second;
    constexpr pair() : first(), second() { }
};

template <typename T, int N> struct array {
    T m_elems[N];
    constexpr int size() const noexcept {
        return N;
    }
};

using IntMapT = array<pair<int, int>, 17>;
static_assert(IntMapT().size() == 17, "BOOM");

int main() { }

C:\Temp>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24103 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

C:\Temp>cl /EHsc /nologo /W4 /MTd meow.cpp
meow.cpp
meow.cpp(15): error C2131: expression did not evaluate to a constant
meow.cpp(15): note: failure was caused by call of undefined function or one not declared 'constexpr'
meow.cpp(15): note: see usage of 'array<pair<int,int>,17>::array'

This example satisfies all of the criteria for a good repro. (It's also accepted by the latest versions of Clang and GCC.)

Example: Library-Free Repro, Accepts-Invalid

Here's another example, where VC should be emitting a compiler error, but isn't.

C:\Temp>type meow.cpp
class Base { };
class Derived : private Base { };
#include <stdio.h>
int main() {
    Base * b = nullptr;
    (void) static_cast<Derived *>(b);
    puts("This shouldn't compile!");
    puts("static_cast shouldn't be able to bypass private inheritance!");
}

C:\Temp>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24103 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

C:\Temp>cl /EHsc /nologo /W4 /MTd meow.cpp && meow
meow.cpp
This shouldn't compile!
static_cast shouldn't be able to bypass private inheritance!

Clang 3.8.0 on Wandbox emits:

prog.cc:6:12: error: cannot cast private base class 'Base' to 'Derived'
    (void) static_cast<Derived *>(b);
           ^
prog.cc:2:17: note: declared private here
class Derived : private Base { };
                ^~~~~~~~~~~~

And GCC 6.1.0:

prog.cc: In function 'int main()':
prog.cc:6:36: error: 'Base' is an inaccessible base of 'Derived'
     (void) static_cast<Derived *>(b);
                                    ^

Note that this repro counts as library-free because even though it's calling puts(), that's unrelated to the compiler error or lack thereof. Similarly, it's okay for compiler bug repros to use printf() or even cout to print stuff, as long as you're using them correctly.

Example: STL Repro

Here's an example of code that was accepted by VC 2010, but rejected by VC 2015. (VC 2012 was the first release to reject this.)

C:\Temp>type meow.cpp
#include <vector>
using namespace std;

int main() {
    vector<vector<int>> matrix(5, 7);
}

C:\Temp>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24103 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

C:\Temp>cl /EHsc /nologo /W4 /MTd meow.cpp
meow.cpp
meow.cpp(5): error C2664: 'std::vector<std::vector<int,std::allocator<_Ty>>,std::allocator<std::vector<
_Ty,std::allocator<_Ty>>>>::vector(std::initializer_list<std::vector<_Ty,std::allocator<_Ty>>>,
const std::allocator<std::vector<_Ty,std::allocator<_Ty>>> &)': cannot convert argument 2 from 'int'
to 'const std::vector<int,std::allocator<_Ty>> &'
        with
        [
            _Ty=int
        ]
meow.cpp(5): note: Reason: cannot convert from 'int' to 'const std::vector<int,std::allocator<_Ty>>'
        with
        [
            _Ty=int
        ]
meow.cpp(5): note: Constructor for class 'std::vector<int,std::allocator<_Ty>>' is declared 'explicit'
        with
        [
            _Ty=int
        ]

This is also an example of an intentional breaking change between C++03 and C++11. If you encountered this issue while upgrading and submitted this repro, we'd be able to instantly diagnose it, tell you what happened, and how to fix your code.

Example: Preprocessed Repro

Sometimes it's not obvious how to eliminate the use of a third-party library. That's okay - for compiler errors, it's almost always possible to provide a self-contained preprocessed repro, which is still easier to investigate than an IDE project.

Here's an example of a repro that's minimal except for the fact that it's using Boost 1.60.0. First, let's look at the compiler error:

C:\Temp>type meow.cpp
#include <tuple>
#include <boost/none.hpp>
#include <boost/optional.hpp>

int main() {
    std::tuple<boost::none_t> t1(boost::none);
    std::tuple<boost::optional<int>> t2(t1);
}

C:\Temp>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24103 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

C:\Temp>cl /EHsc /nologo /W4 /MTd /Iboost_1_60_0 meow.cpp
meow.cpp
boost_1_60_0\boost/optional/optional.hpp(618): error C2440: 'initializing': cannot convert from
'std::tuple<boost::none_t>' to 'int'
boost_1_60_0\boost/optional/optional.hpp(618): note: No user-defined-conversion operator available
that can perform this conversion, or the operator cannot be called
boost_1_60_0\boost/optional/optional.hpp(308): note: see reference to function template instantiation
'void boost::optional_detail::optional_base<T>::construct<std::tuple<boost::none_t>&>(Expr,const void *)'
being compiled
[...template instantiation context omitted in this document; you would provide it in an actual repro...]
meow.cpp(7): note: see reference to function template instantiation
'std::tuple<boost::optional<int>>::tuple<std::tuple<boost::none_t>&,,0>(_This2)' being compiled
        with
        [
            _This2=std::tuple<boost::none_t> &
        ]

We can tell the compiler to just preprocess instead of actually compiling. That's the /P option, which preprocesses meow.cpp into a meow.i file.

C:\Temp>cl /EHsc /nologo /W4 /MTd /Iboost_1_60_0 /P meow.cpp
meow.cpp

The final step is to compile the already-preprocessed file, verifying that we get the same compiler error. In this command line, the changes are (1) eliminating any /D macro definitions and /I include paths because preprocessing has already used them, (2) eliminating /P (which preprocessed, but now we want to compile for real), and (3) replacing meow.cpp with /TP meow.i which tells the compiler to treat that .i extension as C++.

C:\Temp>cl /EHsc /nologo /W4 /MTd /TP meow.i
meow.i
boost_1_60_0\boost/optional/optional.hpp(618): error C2440: 'initializing': cannot convert from
'std::tuple<boost::none_t>' to 'int'
boost_1_60_0\boost/optional/optional.hpp(618): note: No user-defined-conversion operator available
that can perform this conversion, or the operator cannot be called
boost_1_60_0\boost/optional/optional.hpp(308): note: see reference to function template instantiation
'void boost::optional_detail::optional_base<T>::construct<std::tuple<boost::none_t>&>(Expr,const void *)'
being compiled
[...template instantiation context omitted in this document; you would provide it in an actual repro...]
meow.cpp(7): note: see reference to function template instantiation
'std::tuple<boost::optional<int>>::tuple<std::tuple<boost::none_t>&,,0>(_This2)' being compiled
        with
        [
            _This2=std::tuple<boost::none_t> &
        ]

We got the same compiler error, so this is a valid preprocessed repro. You would submit all of this command-line output, the original meow.cpp, and the preprocessed meow.i (which is usually large, so you can zip it).

This example is an intentional breaking change in C++17, specific to 1-tuples. It's also triggered by an improperly constrained boost::optional constructor, which we reported to Boost (it was fixed in a later release).

Other Repros

If you can't reduce an issue to a single source file or a preprocessed repro, we can investigate an IDE project. The guidance above is still relevant - remember, we need to reproduce what you're seeing.

In some situations (e.g. issues that involve Link-Time Code-Gen), the compiler back-end team may need a "link repro". This is uncommon; if we need one, we can give you instructions.

Clone this wiki locally