Microsoft have made over 20 breaking changes to the C++ compiler for Whidbey. The Microsoft development team would love to get feedback on these changes and so have provided the following explanations, workarounds, scenarios and rationales behind their decision to change the compiler.
Note this is preliminary information and is subject to change.
Code written for previous versions of the compiler that just use the method name will give an error
This is Standard C++. Conformance demands that in order to create a pointer to a member function, the address of operator (&) is used with the fully qualified name of the method.
Customer should fully qualify his method name and use the address of operator (&) in order to create a pointer to a member function. It's a common cause for bugs when we can't tell if the customer just forgot a parenthesis in a function call versus he wants to create a pointer to a member function.
Our rationale for making this enforcement other than conform to the C++ Standard, is that in many cases it lead customers to logical bugs in their code due missing parenthesis in function calls. Using the function's name without an argument list results in a function pointer which is convertible to several types, thus the code would have compiled leading to unexpected behavior at runtime.
Customers that want their code to generate MSIL and use the __asm int 3 instruction to generate a break point will need to modify their code.
Before __asm int 3 was translated by the compiler to a CLR break instruction and did not cause native code to be generated when compiled with /clr.
Customer must now use __debugbreak so that the function may be compiled to MSIL and still act as a break point.
We want to be more deterministic about when we generate native code or managed code instead of special casing inline assembly code when targeting the CLR. Inline assembly code should generate native code.
Users that depended on an explicit template specialization for a copy constructor or copy assignment operator in their code will now get compiler error C2299.
Standard C++ prohibits this and as so we changed it to be conformant. Users will need to update their code.
Customer workaround is to stop making the copy constructor/copy asignment operator a template function and just make it a regular function that takes a class type with the desired template arguments. Any code that calls the copy contructor/copy assignment operator by explicitly specifying the template arguments needs to remove the template arguments.
C++ Standard conformance is always on our list of priorities; users expect their code to be portable. We made this change to be conformant.
Users that use an unspecialized template class name in the base class list for a the class' definition will see a compiler error.
It is illegal to use an unspecialized template class name as a template parameter in a base class list. Elsewhere inside the class, the compiler injects the unspecialized type parameter
User needs to explicitly add the template type parameters to the template class name when using it as a template parameter in a base class list.
C++ Standard conformance is always on our list of priorities; users expect their code to be portable. We made this change to be conformant.
Customers that have a using declaration with a nested type will now get C2885.
Before users where allowed to bring in a nested type's declaration to global scope by a using declaration. This is not allowed in Standard C++.
Customer workaround is to fully qualify his nested type whenever he wants to use it. A typedef can also be used to bypass using the scope resolution operator everywhere.
The using declaration cannot be used with nested classes, the C++ Standard specifies that it can be used to bring a class into the scope that is contained in a namespace, not a class.
Users were incorrectly allowed to use const_cast to down cast (cast down the hierarchy to a more derived class type) with our 7.0 and 7.1 compilers. User code like this will now hit compiler error C2440.
This is incorrect code. By definition const_cast can only be used to remove/add a cv qualifier. Any other use of it is incorrect.
Customer workaround it to concatenate use of const_cast with one of our other casts that can down cast (dynamic_cast, static_cast or __try_cast).
The C++ Standard indicates that const_cast should be used to add or remove a const volatile qualifier; to allow it to behave differently special case on managed types was wrong.
Declaring and not defining a managed enum (/clr or /clr:oldSyntax) will give a compiler error. Code written for the VC7.0 and VC7.1 compilers will break.
This used to compile in VC7.0 and VC7.1, but was not guaranteed to work correctly. The problem is the compiler can't correctly identify the underlying type of the enum.
Customer should always define his managed enums at declaration
Managed enums can have different underlying types. We have no syntax for specifying an underlying type in an enum declaration; also the C++ Standard does not allow enum declarations.
Users used this switch to generate automatic pre-compiled headers support for their code. It was used by default from the IDE.
We have other switches that the user can use to add pre-compiled headers support that are better.
Customer can use /Yc and /Yu for pre compiled headers support.
This switch sometimes behaved incorrectly. We prefer customers use /Yc and /Yu which give the user more control.
Users will need to remove these from their projects.
These switches are both replaced by others or not needed anymore
Customer can use the /fp switches for floating point optimizations.
Compiler options /Oa and /Ow usually led people to generate bad code and /Op was replaced by the better /fp switches; these provide the user with better control.
Users that depended on statically linking to the single threaded CRT.
There is no single threaded CRT anymore
Customer can just use /MT and /MTd respectively
We stopped making a single threaded C Runtime Library (CRT) and thus we do not need this compiler option anymore.
Users will need to remove these from their projects.
The processor specific optimization switches can be replaced by our /OX family of switches.
Customer can achieve the same functionality using our /OX family of optimization switches.
Compiler options /G3 - /G7 targeted specific processors, most of which are no longer mass marketed. The user can achieve the same optimizations with our Ox compiler options. For 64 bit development, we added a new optimization switch: /Favor:[ALL|AMD64|EM64T]. Compiler option /Gf enabled string pooling but used writeable memory which is dangerous, /GF achieves the same functionality in safer readonly memory. Compiler option /GD's functionality can be achieved with our other optimizaton options; we do not need specific DLL optimizations. Compiler options /GM and /GB are not needed anymore.
Users will need to replace /MT with /MD for their code targeting .NET
There is no support in the CRT for statically linking managed applications.
Customer needs to change /MT to /MD and link dynamically to the CRT.
There is no support in the C Runtime Library to statically link to a managed application. All managed applications have to be dynamically linked; thus the reason to make the two compiler options conflict.
Users now get buffer overflow checks by default in their code.
This is a good thing. If you are getting errors with this switch it is very likely that the user code has a security flaw.
Customer can turn the option of with /GS-
We want our users to always benefit from the security checks /GS provides.
This will break binary compatibilty when client code is linked with libraries that were compiled without Zc:wchar_t
This is Standard C++ behavior: A wchar_t variable will default to a built in type instead of a short unsigned integer.
Customer can use newly introduced compiler switch /Zc:wchar_t- to revert to the old non-standard behavior.
This compiler option was introduced to correct a conformance discrepancy we shipped with once and still give users a way to revert to the old behavior. We want our users code to be conformant by default.
Code bases that depend on usage of the for scope declared variable after block scope has ended will break fail to compile.
This is Standard C++ behavior: A for scope declared variable will not persist outside the for block scope.
Customer can use newly introduced compiler switch /Zc:forScope- to revert to the old non-standard behavior.
This compiler option was introduced to correct a conformance discrepancy we shipped with once and still give users a way to revert to the old behavior. We want our users code to be conformant by default.
User code that passes named attributes to the attribute constructor in quotes when type is not a string and without quotes when type is a string will stop compiling
Previously all compiler attributes were parsed as strings, hence either [threading(�apartment�)] and [threading(apartment)] worked because the compiler will put in the missing quotes. In passing named arguments to attributes, the type is enforced always.
The compiler displays a hint that you should try the quoted or unquoted version of the parameter in this scenario. User will need to fix their code.
We enhanced our attribute support by adding parameter checking validation. This way our customers will not run into unexpected behavior due to incorrect arguments to an attribute constructor.
Old syntax code that uses the uuid attribute on managed targets
We used to map the uuid attribute to the BCL's GuidAttribute when we parsed it on managed type targets.
Customer should use the BCL's GuidAttribute attribute when targeting managed types
The .NET Framework provides a UUID attribute to be used with managed targets. We want our users to use this and not change the code for them behind the scenes.
Old syntax code that uses user defined custom attributes that take CLI arrays in the contructor needs to be updated.
The type of the array is not deduced anymore from the aggregate initialization list. We now need to specify the type along with the initializer list.
Customer needs to explicitly specify the type of the array with the aggreagate initialization as so: [Attr(new String*[] {"a", "B"}]
The compiler could not always correctly deduce the array type from the aggregate initialization list: { 1, 'c', 1i64 }, what is the array type here? Thus we wanted the user to be more specific and use a syntax similar to the syntax we added for aggregate initialization of CLI arrays in the new syntax.
Code that referenced the attribute name without the suffix outside an attribute block will fail to compile
Compiler will only consider the name without its suffix inside an attribute code block. Elsewhere the class name should follow normal C++ look up rules and should be referenced with its full name
Users need to append the Attribute suffix to their references and conform to C++ look up rules to fix their code
We did this to resolve ambiguous look up cases between non attribute managed classes and attribute managed classes. For example if there exists ref class A and ref class AAttribute : System::Attribute what type is A ^a?
Code out there that was missing the type in a declaration will no longer default to int and will err.
This is Standard C++. The compiler should not be assuming a default type of int in any declaration: whether a function or a variable.
Customer should fix his code or disable the warning that is treated as an error by default (C4430)
Standard C++ does not support a default int. We also wanted to make this change because it is very likely that the user did not intend a return type of int and just forgot to write the desired return type.
User code that depended on a type initializer to run before instantiation of an object of its type might behave incorrectly
In previous versions of our compiler, we emitted a default constructor for value types and this caused the type initializer for the class to run before any objects of the class type get created; it would also run before any static data gets referenced. Now, we only guarantee the latter since there is no longer a default constructor being emitted.
Customer needs to conform their code to the new rules for when the type initializer is guaranteed to run, or force it to run explicitly.
There were two reasons we took into account for not providing a default constructor for value types: the CLR could not guarantee that they would always call it (thus making code erratic or inconsistent at runtime) and a performance increase.
Users that depended on these being public by default.
The compiler will assume private on native types that did not specify a class accessibility modifier. In 7.0 it would behave the same way. The 7.1 compiler would assume public which led to some unexpected and negative side effects.
User will have to explicitly put a public accessibility specifier in the native class declaration if they want it to be public.
We had different reasons to go back to the 7.0 behavior on native types in a managed compilation. When an assembly was imported namespaces where polluted with irrelevant native types that were brought in. This caused interoperability problems with other languages like VB.NET that were case insensitive and thus there were name conflicts. We think that native types used in an assembly should be left as an implementation detail and thus made private by default. If the user desires the contrary behavior, he can always use the public accessibility class modifier.
Code written for Managed Extensions for C++ that is harnessed to compile with the /clr switch
We changed the meaning of the /clr switch to now default to our new C++ syntax to target the CLR instead of the old one shipped with previous versions of the compiler
Change /clr to /clr:oldSyntax to compile code written with Managed Extensions for C++
The new syntax language is the way to go when targetting the .NET platform using C++. We want users to get the benefits from this new rich experience by default.
Users that compiled files with .c extension or with command line options /TC or /Tc with any switch from the /clr family will see an error.
The C language does not support the CLR
User can change the file extension to .cpp|.cxx or compile with the /TP or /Tp command line options
We provide a C++ language to target the .NET platform, not a C language, thus the C language does not support the CLR. With this in mind we made that compilation scenario invalid.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||