Click here to Skip to main content
Click here to Skip to main content

Rationale Behind Whidbey C++ Breaking Changes

, 6 Feb 2005 CPOL
Rate this:
Please Sign up or sign in to vote.
The explanations, workarounds, scenarios and the rationale behind the decisions to change the Whidbey C++ compiler.

Introduction

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.

 

1. Pointer-to-members now require qualified name and &.

Affected User Scenario:

Code written for previous versions of the compiler that just use the method name will give an error 

Description:

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 Workaround:

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. 

Rationale:

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.

2. __asm int 3 now generates native code

Affected User Scenario:

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. 

Description:

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 Workaround:

Customer must now use __debugbreak so that the function may be compiled to MSIL and still act as a break point. 

Rationale:

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.

3. Explicit  specialization not allowed as a copy constructor/copy assignment operator

Affected User Scenario:

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. 

Description:

Standard C++ prohibits this and as so we changed it to be conformant.  Users will need to update their code. 

Customer Workaround:

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. 

Rationale:

C++ Standard conformance is always on our list of priorities; users expect their code to be portable.  We made this change to be conformant. 

4. Unspecialized class template can't be used as a template argument in a base class list

Affected User Scenario:

Users that use an unspecialized template class name in the base class list for a the class' definition will see a compiler error. 

Description:

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 

Customer Workaround:

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. 

Rationale:

C++ Standard conformance is always on our list of priorities; users expect their code to be portable.  We made this change to be conformant. 

5. A using declaration of nested type is now illegal

Affected User Scenario:

Customers that have a using declaration with a nested type  will now get C2885. 

Description:

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:

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. 

Rationale:

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. 

6. Compiler no longer allows const_cast to down cast in the old syntax.

Affected User Scenario:

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.   

Description:

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:

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). 

Rationale:

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. 

7. Compiler disallows forward declaration of a managed enum

Affected User Scenario:

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. 

Description:

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 Workaround:

Customer should always define his managed enums at declaration 

Rationale:

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. 

8. Switch removal: /YX

Affected User Scenario:

Users used this switch to generate automatic pre-compiled headers support for their code.  It was used by default from the IDE. 

Description:

We have other switches that the user can use to add pre-compiled headers support that are better. 

Customer Workaround:

Customer can use /Yc and /Yu for pre compiled headers support. 

Rationale:

This switch sometimes behaved incorrectly.  We prefer customers use /Yc and /Yu which give the user more control. 

9. Switch removal: Optimizations /Oa, /Op and /Ow

Affected User Scenario:

Users will need to remove these from their projects. 

Description:

These switches are both replaced by others or not needed anymore 

Customer Workaround:

Customer can use the /fp switches for floating point optimizations. 

Rationale:

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. 

10. Switch removal: /ML and /MLd

Affected User Scenario:

Users that depended on statically linking to the single threaded CRT. 

Description:

There is no single threaded CRT anymore 

Customer Workaround:

Customer can just use /MT and /MTd respectively 

Rationale:

We stopped making a single threaded C Runtime Library (CRT) and thus we do not need this compiler option anymore. 

11. Switch removal: /G3 - /G7, /GB, /Gf, /GD, /GM

Affected User Scenario:

Users will need to remove these from their projects. 

Description:

The processor specific optimization switches can be replaced by our /OX family of switches. 

Customer Workaround:

Customer can achieve the same functionality using our /OX family of optimization switches. 

Rationale:

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. 

12. Switch conflict: /clr and /MT

Affected User Scenario:

Users will need to replace /MT with /MD for their code targeting .NET 

Description:

There is no support in the CRT for statically linking managed applications.  

Customer Workaround:

Customer needs to change /MT to /MD and link dynamically to the CRT. 

Rationale:

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. 

13. Switch change: /GS turned on by default.

Affected User Scenario:

Users now get buffer overflow checks by default in their code. 

Description:

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 Workaround:

Customer can turn the option of with /GS- 

Rationale:

We want our users to always benefit from the security checks /GS provides. 

14. Switch change: /Zc:wchar_t turned on by default

Affected User Scenario:

This will break binary compatibilty when client code is linked with libraries that were compiled without Zc:wchar_t 

Description:

This is Standard C++ behavior: A wchar_t variable will default to a built in type instead of a short unsigned integer. 

Customer Workaround:

Customer can use newly introduced compiler switch /Zc:wchar_t- to revert to the old non-standard behavior. 

Rationale:

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. 

15. Switch change: /Zc:forScope turned on by default

Affected User Scenario:

Code bases that depend on usage of the for scope declared variable after block scope has ended will break fail to compile. 

Description:

This is Standard C++ behavior: A for scope declared variable will not persist outside the for block scope. 

Customer Workaround:

Customer can use newly introduced compiler switch /Zc:forScope- to revert to the old non-standard behavior. 

Rationale:

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.

16. Enforcing parameter checking for vc attributes

Affected User Scenario:

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 

Description:

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. 

Customer Workaround:

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. 

Rationale:

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. 

17. uuid attribute can no longer target managed types

Affected User Scenario:

Old syntax code that uses the uuid attribute on managed targets 

Description:

We used to map the uuid attribute to the BCL's GuidAttribute when we parsed it on managed type targets. 

Customer Workaround:

Customer should use the BCL's GuidAttribute attribute when targeting managed types 

Rationale:

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. 

18. The syntax changed for passing CLI arrays to custom attributes

Affected User Scenario:

Old syntax code that uses user defined custom attributes that take CLI arrays in the contructor needs to be updated. 

Description:

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 Workaround:

Customer needs to explicitly specify the type of the array with the aggreagate initialization as so: [Attr(new String*[] {"a", "B"}] 

Rationale:

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. 

19. Attribute look up changes - compiler will only find non-suffixed attribute name inside attribute block

Affected User Scenario:

Code that referenced the attribute name without the suffix outside an attribute block will fail to compile 

Description:

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 

Customer Workaround:

Users need to append the Attribute suffix to their references and conform to C++ look up rules to fix their code 

Rationale:

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? 

20. Compiler will not inject a default type int in declarations missing a type

Affected User Scenario:

Code out there that was missing the type in a declaration will no longer default to int and will err. 

Description:

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 Workaround:

Customer should fix his code or disable the warning that is treated as an error by default (C4430) 

Rationale:

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. 

21. Valuetypes no longer have a default constructor emitted – this can cause type initializers to run at different points

Affected User Scenario:

User code that depended on a type initializer to run before instantiation of an object of its type might behave incorrectly 

Description:

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 Workaround:

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. 

Rationale:

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. 

22. Native types are private by default in a managed compilation

Affected User Scenario:

Users that depended on these being public by default. 

Description:

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. 

Customer Workaround:

User will have to explicitly put a public accessibility specifier in the native class declaration if they want it to be public. 

Rationale:

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.   

23. Switch change: The /clr switch will now compile new syntax C++ code and not Managed Extensions for C++ syntax

Affected User Scenario:

Code written for Managed Extensions for C++ that is harnessed to compile with the /clr switch 

Description:

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 

Customer Workaround:

Change /clr to /clr:oldSyntax to compile code written with Managed Extensions for C++ 

Rationale:

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. 

24. Switch change: C compilands are not supported with /clr

Affected User Scenario:

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. 

Description:

The C language does not support the CLR 

Customer Workaround:

User can change the file extension to .cpp|.cxx or compile with the /TP or /Tp command line options 

Rationale:

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Chris Maunder
Founder CodeProject
Canada Canada
Chris is the Co-founder, Administrator, Architect, Chief Editor and Shameless Hack who wrote and runs The Code Project. He's been programming since 1988 while pretending to be, in various guises, an astrophysicist, mathematician, physicist, hydrologist, geomorphologist, defence intelligence researcher and then, when all that got a bit rough on the nerves, a web developer. He is a Microsoft Visual C++ MVP both globally and for Canada locally.
 
His programming experience includes C/C++, C#, SQL, MFC, ASP, ASP.NET, and far, far too much FORTRAN. He has worked on PocketPCs, AIX mainframes, Sun workstations, and a CRAY YMP C90 behemoth but finds notebooks take up less desk space.
 
He dodges, he weaves, and he never gets enough sleep. He is kind to small animals.
 
Chris was born and bred in Australia but splits his time between Toronto and Melbourne, depending on the weather. For relaxation he is into road cycling, snowboarding, rock climbing, and storm chasing.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
QuestionExamples? PinmemberLuca Piccarreta6-Feb-05 18:05 
AnswerRe: Examples? PinmemberOne Stone6-Feb-05 22:45 
GeneralRe: Examples? PinmemberLuca Piccarreta7-Feb-05 3:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411022.1 | Last Updated 6 Feb 2005
Article Copyright 2005 by Chris Maunder
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid