This is an archive of the discontinued LLVM Phabricator instance.

Lit C++11 Compatibility Patch #11
ClosedPublic

Authored by tigerleapgorge on Sep 21 2016, 12:00 PM.

Details

Summary

5 tests have been updated to be C++11 compatible.
Here are the explanations for each test.

CodeGenCXX/mangle-unnamed.cpp

Test section f6() verifies the mangled name of the variable b that is inside 
the static anonymous union along with an anonymous union of a unnamed bit field.

Running this test in C++11 results in the following error.
  error: call to implicitly-deleted default constructor of '(anonymous union at t.cpp:2:10)'
  note: default constructor of '' is implicitly deleted because field '' has a deleted default constructor
  note: default constructor of '' is implicitly deleted because all data members are const-qualified

This is most likely due to interaction between three parts of the C++11 standard:
  1. Unnamed bit-field cannot be initialized.
       C++ Standard section 9.6.2 [class.bit]
          A declaration for a bit-field that omits the identifier declares an unnamed bit-field.
          Unnamed bit-fields are not members and cannot be initialized.
  2. Introduction of keyword “delete”. 
  3. Change in rules regarding Unions.
       http://www.stroustrup.com/C++11FAQ.html#unions
         If a union has a member with a user-defined constructor, copy, or destructor
         then that special function is deleted;
         that is, it cannot be used for an object of the union type. This is new.

For f6(), Since the unnamed bitfield “int : 1;” can not be initialized, 
its constructor is considered “deleted”, therefore it cannot be used inside a union.
Hence f6() would be an invalid test for C++11.

Since this test verifies for name managling, I have restricted f6() to C++98.

CodeGenCXX/static-init.cpp

Inside test4,
The LLVM IR for useStaticLocal() has been greatly simplified in C++11.
This is likely due to C++11 Standard section 6.7.4 [stmt.dcl]

  The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1)
  or thread storage duration (3.7.2) is performed before any other initialization takes place.

Since Struct HasVTable only has a virtual method f that is declared but not defined,
Clang likely assumed that no initialization is needed inside routine useStaticLocal().
Therefore Clang in C++11 no longer generates the default contructors for HasVTable nor 
the singleton pattern to guard against reinitialization of HasVTable.

Relevant IR changes are shown below.

C++98 IR:
  @_ZZN5test414useStaticLocalEvE3obj = linkonce_odr global %"struct.test4::HasVTable" zeroinitializer, comdat, align 8
  @_ZGVZN5test414useStaticLocalEvE3obj = linkonce_odr global i64 0, comdat, align 8

  ; Function Attrs: inlinehint nounwind
  define linkonce_odr dereferenceable(8) %"struct.test4::HasVTable"* @_ZN5test414useStaticLocalEv() #4 comdat {
  entry:
    %0 = load atomic i8, i8* bitcast (i64* @_ZGVZN5test414useStaticLocalEvE3obj to i8*) acquire, align 8
    %guard.uninitialized = icmp eq i8 %0, 0
    br i1 %guard.uninitialized, label %init.check, label %init.end

  init.check:                                       ; preds = %entry
    %1 = call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test414useStaticLocalEvE3obj) #1
    %tobool = icmp ne i32 %1, 0
    br i1 %tobool, label %init, label %init.end

  init:                                             ; preds = %init.check
    call void @_ZN5test49HasVTableC1Ev(%"struct.test4::HasVTable"* @_ZZN5test414useStaticLocalEvE3obj) #1
    call void @__cxa_guard_release(i64* @_ZGVZN5test414useStaticLocalEvE3obj) #1
    br label %init.end

  init.end:                                         ; preds = %init, %init.check, %entry
    ret %"struct.test4::HasVTable"* @_ZZN5test414useStaticLocalEvE3obj
  }

  ; Function Attrs: inlinehint nounwind
  define linkonce_odr void @_ZN5test49HasVTableC1Ev(%"struct.test4::HasVTable"* %this) unnamed_addr #4 comdat align 2 {
  entry:
    %this.addr = alloca %"struct.test4::HasVTable"*, align 8
    store %"struct.test4::HasVTable"* %this, %"struct.test4::HasVTable"** %this.addr, align 8
    %this1 = load %"struct.test4::HasVTable"*, %"struct.test4::HasVTable"** %this.addr, align 8
    call void @_ZN5test49HasVTableC2Ev(%"struct.test4::HasVTable"* %this1) #1
    ret void
  }

  ; Function Attrs: inlinehint nounwind
  define linkonce_odr void @_ZN5test49HasVTableC2Ev(%"struct.test4::HasVTable"* %this) unnamed_addr #4 comdat align 2 {
  entry:
    %this.addr = alloca %"struct.test4::HasVTable"*, align 8
    store %"struct.test4::HasVTable"* %this, %"struct.test4::HasVTable"** %this.addr, align 8
    %this1 = load %"struct.test4::HasVTable"*, %"struct.test4::HasVTable"** %this.addr, align 8
    %0 = bitcast %"struct.test4::HasVTable"* %this1 to i32 (...)***
    store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @_ZTVN5test49HasVTableE, i32 0, i32 2) 
                              to i32 (...)**), i32 (...)*** %0, align 8
    ret void
  }

C++11 IR:
  @_ZZN5test414useStaticLocalEvE3obj = linkonce_odr global { i8** } { i8** getelementptr inbounds ([3 x i8*], 
                                       [3 x i8*]* @_ZTVN5test49HasVTableE, i32 0, i32 2) }, comdat, align 8

  ; Function Attrs: inlinehint nounwind
  define linkonce_odr dereferenceable(8) %"struct.test4::HasVTable"* @_ZN5test414useStaticLocalEv() #5 comdat {
  entry:
    ret %"struct.test4::HasVTable"* bitcast ({ i8** }* @_ZZN5test414useStaticLocalEvE3obj to %"struct.test4::HasVTable"*)
  }

CodeGenCXX/volatile-1.cpp

In C++11, volatile accesses in discarded-value expressions generate loads in the LLVM IR.
Add the “load volatile” for the following cases.

  i;
  (void)ci;
  (void)i;
  (void)(i,(i=i));
  i=i,k;
  (i=j,k);
  (i,j);
  ci;
  (i,j)=k;

CodeGenCXX/volatile.cpp

This test checks for the IR of volatile pointer dereferences.
In C++11, *x; resulted in an additional “load volatile”.
This is because *x; is an indirection of the volatile qualified x inside a discarded-value expression.
http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1054
And according to the standard defect fix 1054, this is now an use of x.
http://stackoverflow.com/questions/20242868/correct-behaviour-of-trivial-statements-involving-expressions-with-volatile-vari

Expect the following extra line of IR in C++11.

Existing:  %0 = load i32*, i32** @_ZN5test11xE, align 8
C++11:     %1 = load volatile i32, i32* %0, align 4
Existing:  ret void

PCH/macro-undef.cpp

This test uses uninitialized variable diagnostics to verify macro undef behavior across PCH export and import.

This test is compiled 3 times.
1st time, the function template definitions for f() and g() are exported to a PCH file.
2nd time, the PCH is imported to compile the main() function. Inside main, f() and g() are instantiated. The diagnostics is checked.
3nd time, the PCH is imported to compile the main() function. Inside main, f() and g() are instantiated. The fix-it line of the diagnostics is checked.
         The fix-it line differs depending on if the macro NULL is defined or undefined.
         However, because C++11 introduced ‘nullptr’, the fix-it message no longer differs.

In C++98, when NULL is defined to 0, the fix it message will use NULL (at line 11) 
          When NULL is undefined, the fix it message will use 0 (at line 17).
In C++11, the fix it message will use ‘nullptr’ whether or not NULL is defined or undefined.

C++98: note: initialize the variable 'p' to silence this warning
         void *p;  // @11
                ^
                 = NULL

       note: initialize the variable 'p' to silence this warning
         void *p;  // @17
                ^
                 = 0

C++11: note: initialize the variable 'p' to silence this warning
       void *p;  // @11
              ^
               = nullptr

       note: initialize the variable 'p' to silence this warning
         void *p;  // @17
                ^
                 = nullptr


Since this test is meant to test macro undef behavior and that the C++11 fix-it diagnostics can not distinguish between the macro being defined to “NULL” vs being undefined (nullptr in both cases), I have restricted this test to C++98.

Cheers,
Charles Li

Diff Detail

Repository
rL LLVM

Event Timeline

tigerleapgorge retitled this revision from to Lit C++11 Compatibility Patch #11.
tigerleapgorge updated this object.
tigerleapgorge added a reviewer: rsmith.
tigerleapgorge added a subscriber: cfe-commits.
tigerleapgorge updated this revision to Diff 81987.EditedDec 19 2016, 1:17 PM
tigerleapgorge updated this object.

Update Lit patch #11 to match latest Clang behavior
2 minor changes in this update

  1. Back out test/CodeGenCXX/mangle-unnamed.cpp because it has already been fixed.
  1. Modified test/CodeGenCXX/static-init.cpp to match latest IR.

Also, this patch contained full context diff while the previous one does not.
Previous revision: svn diff
This revision svn diff --diff-cmd=diff -x -U999999

Also reordered the summery to match up to the order of tests as they appear in the patch.

Revise again,

D28425 fixed 7 tests.
r290229 fixed 1 test.

Down to 8 tests.

tigerleapgorge edited the summary of this revision. (Show Details)Feb 2 2017, 5:08 PM
probinson added a subscriber: probinson.

+rjmccall as CodeGen owner.

tigerleapgorge edited the summary of this revision. (Show Details)Feb 2 2017, 6:10 PM
tigerleapgorge edited the summary of this revision. (Show Details)

Remove another 3 tests reviewed in D29859

rjmccall edited edge metadata.

Generally looks good to me, thanks. One question for Reid.

test/CodeGenCXX/static-init.cpp
14 ↗(On Diff #88224)

Interesting. It looks to me like the C++11 IR pattern is actually the only one that would've exposed the bug that Reid was fixing in r242704. Reid, do you agree?

test/CodeGenCXX/volatile.cpp
31 ↗(On Diff #88224)

CHECK11-NEXT, please.

rnk added inline comments.Feb 15 2017, 2:15 PM
test/CodeGenCXX/static-init.cpp
14 ↗(On Diff #88224)

I'm not sure I follow exactly, but I think what's going on here is that, in C++11, the implicit default constructor is constexpr. I'm not sure how that feeds into what type we choose to use for the global.

Changed "CHECK11" to "CHECK11-NEXT".

tigerleapgorge marked an inline comment as done.Feb 15 2017, 3:39 PM

@rjmccall

Hi John, I've made the changes to volatile.cpp.
I take it this patch is good for commit?

rjmccall added inline comments.Feb 16 2017, 8:23 PM
test/CodeGenCXX/static-init.cpp
14 ↗(On Diff #88224)

The global gets created using its formal type, and then we need to give it an initializer, which in some cases will have a different type, and so we need to replace the global with something with the right type. Maybe that's not the type mismatch you were fixing in that revision?

Really I'm telling you to please go ahead and finish your eliminating-types-from-pointer work. :)

@rjmccall

Hi John, I've made the changes to volatile.cpp.
I take it this patch is good for commit?

Yes, I think I have the information I wanted from Reid. LGTM.

This revision was automatically updated to reflect the committed changes.