[cfe-dev] C++11 definition of POD and tail padding

Joshua Magee joshua_magee at playstation.sony.com
Tue Jul 2 19:15:10 PDT 2013


Hi,

Attached is a testcase that will or will not use tail padding depending on the
language mode (C++03 versus C++11).  The test uses a class that is POD in C++11
but non-POD in C++03.  Using a recent TOT of compiler (clang r185419), the
compiler will use the tail padding in C++03 mode but will not use it in C++11
mode.

The Itanium C++ ABI (http://mentorembedded.github.io/cxx-abi/abi.html) has a
clause which states that for the purpose of layout the C++03 definition of POD
should be used:

" POD for the purpose of layout

  ...

  There have been multiple published revisions to the ISO C++ standard,
  and each one has included a different definition of POD. To ensure
  interoperation of code compiled according to different revisions of
  the standard, it is necessary to settle on a single definition for a
  platform. A platform vendor may choose to follow a different revision
  of the standard, but by default, the definition of POD under this ABI
  is the definition from the 2003 revision (TC1).
"

Furthermore, r173744 refactored the RecordLayoutBuilder code and added comments
which suggest that Clang should be following the Itanium ABI with respect
towards the above POD layout rules:
"
// To preserve binary compatibility, the generic Itanium ABI has                 
// permanently locked the definition of POD to the rules of C++ TR1,             
// and that trickles down to all the derived ABIs.
"

Given this, I would expect the attached testcase to use the tail padding even
in C++11 mode.  It seems that code responsible for determining if tail padding
should be used (mustSkipTailPadding) expects that isPOD() checks the C++ TR1
(2003) definition of POD, however the behaviour with this testcase shows that
isPOD is not using the TR1 definition in all cases.

I also attached a small sample patch that at least superficially fixes the
problem by explicitly calling isCXX98PODType() instead of isPODType() when
setting data().PlainOldData (which is what isPOD() returns.)  The patch is not
presented as a real fix, but just to help demonstrate why isPOD() is not
consistently using the TR1 definition of POD.

Should I file a bug about this?

Thanks,
Josh
-------------- next part --------------
// tail-padding.cpp
// 
// Uses tail padding when compiled with:         clang -std=c++03
// Does not use tail padding when compiled with: clang -std=c++11
// Using Target: x86_64-unknown-linux-gnu

#include <stdio.h>

typedef unsigned long long int64;
typedef unsigned char int8;

// non-POD in 03
struct pod_in_11_only
{
private:
  int64 x;
};
 
// non-POD in 03
struct tail_padded_pod_in_11_only {
  pod_in_11_only pod11;
  int8 tail_padding;
};
  
// use tail-padding in 03, don't use in 11
struct might_use_tail_padding : public tail_padded_pod_in_11_only {
  int8 may_go_into_tail_padding;
};

int main() {
    printf("sizeof(might_use_tail_padding) == %lu\n", sizeof(might_use_tail_padding));
    printf("%s\n", sizeof(might_use_tail_padding) == 16 ? "Using tail padding"
                                                        : "NOT using tail padding");
    return 0;
}
-------------- next part --------------
diff --git lib/AST/DeclCXX.cpp lib/AST/DeclCXX.cpp
index 9108095..8ce0f98 100644
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -662,7 +662,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
       if (!Context.getLangOpts().ObjCAutoRefCount ||
           T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
         setHasObjectMember(true);
-    } else if (!T.isPODType(Context))
+    } else if (!T.isCXX98PODType(Context))
       data().PlainOldData = false;
     
     if (T->isReferenceType()) {


More information about the cfe-dev mailing list