r188481 - CodeGen: __uuidof should work even with an incomplete _GUID type

David Majnemer david.majnemer at gmail.com
Thu Aug 15 12:59:14 PDT 2013


Author: majnemer
Date: Thu Aug 15 14:59:14 2013
New Revision: 188481

URL: http://llvm.org/viewvc/llvm-project?rev=188481&view=rev
Log:
CodeGen: __uuidof should work even with an incomplete _GUID type

Summary:
We would crash in CodeGen::CodeGenModule::EmitUuidofInitializer
because our attempt to enter CodeGen::CodeGenModule::EmitConstantValue
will be foiled: the type of the constant value is incomplete.

Instead, create an unnamed type with the proper layout on all platforms.
Punt the problem of wrongly defined struct _GUID types to the user.
(It's impossible because the TU may never get to see the type and thus
we can't verify that it is suitable.)

This fixes PR16856.

Reviewers: rsmith, rnk, thakis

Reviewed By: rnk

CC: cfe-commits

Differential Revision: http://llvm-reviews.chandlerc.com/D1375

Removed:
    cfe/trunk/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-uuidof.cpp

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=188481&r1=188480&r2=188481&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Aug 15 14:59:14 2013
@@ -2995,7 +2995,8 @@ CodeGenFunction::EmitCXXTypeidLValue(con
 }
 
 llvm::Value *CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) {
-  return CGM.GetAddrOfUuidDescriptor(E);
+  return Builder.CreateBitCast(CGM.GetAddrOfUuidDescriptor(E),
+                               ConvertType(E->getType())->getPointerTo());
 }
 
 LValue CodeGenFunction::EmitCXXUuidofLValue(const CXXUuidofExpr *E) {

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=188481&r1=188480&r2=188481&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Thu Aug 15 14:59:14 2013
@@ -1057,22 +1057,9 @@ llvm::Constant *CodeGenModule::GetAddrOf
   llvm::Constant *Init = EmitUuidofInitializer(Uuid, E->getType());
   assert(Init && "failed to initialize as constant");
 
-  // GUIDs are assumed to be 16 bytes, spread over 4-2-2-8 bytes. However, the
-  // first field is declared as "long", which for many targets is 8 bytes.
-  // Those architectures are not supported. (With the MS abi, long is always 4
-  // bytes.)
-  llvm::Type *GuidType = getTypes().ConvertType(E->getType());
-  if (Init->getType() != GuidType) {
-    DiagnosticsEngine &Diags = getDiags();
-    unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
-        "__uuidof codegen is not supported on this architecture");
-    Diags.Report(E->getExprLoc(), DiagID) << E->getSourceRange();
-    Init = llvm::UndefValue::get(GuidType);
-  }
-
-  llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), GuidType,
+  llvm::GlobalVariable *GV = new llvm::GlobalVariable(
+      getModule(), Init->getType(),
       /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, Init, Name);
-  GV->setUnnamedAddr(true);
   return GV;
 }
 
@@ -3077,26 +3064,24 @@ llvm::Constant *CodeGenModule::EmitUuido
   // Sema has checked that all uuid strings are of the form
   // "12345678-1234-1234-1234-1234567890ab".
   assert(Uuid.size() == 36);
-  const char *Uuidstr = Uuid.data();
-  for (int i = 0; i < 36; ++i) {
-    if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuidstr[i] == '-');
-    else                                         assert(isHexDigit(Uuidstr[i]));
-  }
-  
-  llvm::APInt Field0(32, StringRef(Uuidstr     , 8), 16);
-  llvm::APInt Field1(16, StringRef(Uuidstr +  9, 4), 16);
-  llvm::APInt Field2(16, StringRef(Uuidstr + 14, 4), 16);
-  static const int Field3ValueOffsets[] = { 19, 21, 24, 26, 28, 30, 32, 34 };
-
-  APValue InitStruct(APValue::UninitStruct(), /*NumBases=*/0, /*NumFields=*/4);
-  InitStruct.getStructField(0) = APValue(llvm::APSInt(Field0));
-  InitStruct.getStructField(1) = APValue(llvm::APSInt(Field1));
-  InitStruct.getStructField(2) = APValue(llvm::APSInt(Field2));
-  APValue& Arr = InitStruct.getStructField(3);
-  Arr = APValue(APValue::UninitArray(), 8, 8);
-  for (int t = 0; t < 8; ++t)
-    Arr.getArrayInitializedElt(t) = APValue(llvm::APSInt(
-          llvm::APInt(8, StringRef(Uuidstr + Field3ValueOffsets[t], 2), 16)));
+  for (unsigned i = 0; i < 36; ++i) {
+    if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuid[i] == '-');
+    else                                         assert(isHexDigit(Uuid[i]));
+  }
+
+  const unsigned Field3ValueOffsets[8] = { 19, 21, 24, 26, 28, 30, 32, 34 };
+
+  llvm::Constant *Field3[8];
+  for (unsigned Idx = 0; Idx < 8; ++Idx)
+    Field3[Idx] = llvm::ConstantInt::get(
+        Int8Ty, Uuid.substr(Field3ValueOffsets[Idx], 2), 16);
+
+  llvm::Constant *Fields[4] = {
+    llvm::ConstantInt::get(Int32Ty, Uuid.substr(0,  8), 16),
+    llvm::ConstantInt::get(Int16Ty, Uuid.substr(9,  4), 16),
+    llvm::ConstantInt::get(Int16Ty, Uuid.substr(14, 4), 16),
+    llvm::ConstantArray::get(llvm::ArrayType::get(Int8Ty, 8), Field3)
+  };
 
-  return EmitConstantValue(InitStruct, GuidType);
+  return llvm::ConstantStruct::getAnon(Fields);
 }

Removed: cfe/trunk/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp?rev=188480&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp (removed)
@@ -1,13 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-macosx10.8.0 -fms-extensions -verify
-
-typedef struct _GUID
-{
-    unsigned long  Data1;
-    unsigned short Data2;
-    unsigned short Data3;
-    unsigned char  Data4[8];
-} GUID;
-
-struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S { };
-
-GUID g = __uuidof(S);  // expected-error {{__uuidof codegen is not supported on this architecture}}

Modified: cfe/trunk/test/CodeGenCXX/microsoft-uuidof.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-uuidof.cpp?rev=188481&r1=188480&r2=188481&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-uuidof.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-uuidof.cpp Thu Aug 15 14:59:14 2013
@@ -1,80 +1,112 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -triple=i386-pc-win32 -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID
 // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -DWRONG_GUID -triple=i386-pc-win32 -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-WRONG-GUID
 
-typedef struct _GUID
-{
+#ifdef DEFINE_GUID
+struct _GUID {
+#ifdef WRONG_GUID
+    unsigned int SomethingWentWrong;
+#else
     unsigned long  Data1;
     unsigned short Data2;
     unsigned short Data3;
     unsigned char  Data4[8];
-} GUID;
+#endif
+};
+#endif
+typedef struct _GUID GUID;
 
 struct __declspec(uuid("12345678-1234-1234-1234-1234567890aB")) S1 { } s1;
 struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S2 { };
 struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly;
 
+#ifdef DEFINE_GUID
 // Make sure we can properly generate code when the UUID has curly braces on it.
 GUID thing = __uuidof(Curly);
-// CHECK: @thing = global %struct._GUID zeroinitializer, align 4
+// CHECK-DEFINE-GUID: @thing = global %struct._GUID zeroinitializer, align 4
+// CHECK-DEFINE-WRONG-GUID: @thing = global %struct._GUID zeroinitializer, align 4
 
 // This gets initialized in a static initializer.
-// CHECK: @g = global %struct._GUID zeroinitializer, align 4
+// CHECK-DEFINE-GUID: @g = global %struct._GUID zeroinitializer, align 4
+// CHECK-DEFINE-WRONG-GUID: @g = global %struct._GUID zeroinitializer, align 4
 GUID g = __uuidof(S1);
+#endif
 
 // First global use of __uuidof(S1) forces the creation of the global.
-// CHECK: @_GUID_12345678_1234_1234_1234_1234567890ab = unnamed_addr constant %struct._GUID { i32 305419896, i16 4660, i16 4660, [8 x i8] c"\124\124Vx\90\AB" }
-// CHECK: @gr = constant %struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab, align 4
+// CHECK: @_GUID_12345678_1234_1234_1234_1234567890ab = constant { i32, i16, i16, [8 x i8] } { i32 305419896, i16 4660, i16 4660, [8 x i8] c"\124\124Vx\90\AB" }
+// CHECK: @gr = constant %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to %struct._GUID*), align 4
 const GUID& gr = __uuidof(S1);
 
-// CHECK: @gp = global %struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab, align 4
+// CHECK: @gp = global %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to %struct._GUID*), align 4
 const GUID* gp = &__uuidof(S1);
 
-// CHECK: @cp = global %struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ac, align 4
+// CHECK: @cp = global %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to %struct._GUID*), align 4
 const GUID* cp = &__uuidof(Curly);
 
 // Special case: _uuidof(0)
-// CHECK: @zeroiid = constant %struct._GUID* @_GUID_00000000_0000_0000_0000_000000000000, align 4
+// CHECK: @zeroiid = constant %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_00000000_0000_0000_0000_000000000000 to %struct._GUID*), align 4
 const GUID& zeroiid = __uuidof(0);
 
 // __uuidof(S2) hasn't been used globally yet, so it's emitted when it's used
 // in a function and is emitted at the end of the globals section.
-// CHECK: @_GUID_87654321_4321_4321_4321_ba0987654321 = unnamed_addr constant %struct._GUID { i32 -2023406815, i16 17185, i16 17185, [8 x i8] c"C!\BA\09\87eC!" }
+// CHECK: @_GUID_87654321_4321_4321_4321_ba0987654321 = constant { i32, i16, i16, [8 x i8] } { i32 -2023406815, i16 17185, i16 17185, [8 x i8] c"C!\BA\09\87eC!" }
+
+// The static initializer for thing.
+// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @thing to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 16, i32 4, i1 false)
+// CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @thing to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 4, i32 4, i1 false)
 
 // The static initializer for g.
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+// CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false)
 
+#ifdef DEFINE_GUID
 void fun() {
-  // CHECK: %s1_1 = alloca %struct._GUID, align 4
-  // CHECK: %s1_2 = alloca %struct._GUID, align 4
-  // CHECK: %s1_3 = alloca %struct._GUID, align 4
-
-  // CHECK: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8*
-  // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+  // CHECK-DEFINE-GUID: %s1_1 = alloca %struct._GUID, align 4
+  // CHECK-DEFINE-WRONG-GUID: %s1_1 = alloca %struct._GUID, align 4
+  // CHECK-DEFINE-GUID: %s1_2 = alloca %struct._GUID, align 4
+  // CHECK-DEFINE-WRONG-GUID: %s1_2 = alloca %struct._GUID, align 4
+  // CHECK-DEFINE-GUID: %s1_3 = alloca %struct._GUID, align 4
+  // CHECK-DEFINE-WRONG-GUID: %s1_3 = alloca %struct._GUID, align 4
+
+  // CHECK-DEFINE-GUID: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8*
+  // CHECK-DEFINE-WRONG-GUID: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8*
+  // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+  // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false)
   GUID s1_1 = __uuidof(S1);
 
-  // CHECK: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8*
-  // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+  // CHECK-DEFINE-GUID: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8*
+  // CHECK-DEFINE-WRONG-GUID: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8*
+  // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+  // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false)
   GUID s1_2 = __uuidof(S1);
 
-  // CHECK: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8*
-  // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+  // CHECK-DEFINE-GUID: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8*
+  // CHECK-DEFINE-WRONG-GUID: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8*
+  // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+  // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false)
   GUID s1_3 = __uuidof(s1);
 }
+#endif
 
 void gun() {
-  // CHECK: %s2_1 = alloca %struct._GUID, align 4
-  // CHECK: %s2_2 = alloca %struct._GUID, align 4
+#ifdef DEFINE_GUID
+  // CHECK-DEFINE-GUID: %s2_1 = alloca %struct._GUID, align 4
+  // CHECK-DEFINE-WRONG-GUID: %s2_1 = alloca %struct._GUID, align 4
+  // CHECK-DEFINE-GUID: %s2_2 = alloca %struct._GUID, align 4
+  // CHECK-DEFINE-WRONG-GUID: %s2_2 = alloca %struct._GUID, align 4
+  GUID s2_1 = __uuidof(S2);
+  GUID s2_2 = __uuidof(S2);
+#endif
   // CHECK: %r = alloca %struct._GUID*, align 4
   // CHECK: %p = alloca %struct._GUID*, align 4
   // CHECK: %zeroiid = alloca %struct._GUID*, align 4
-  GUID s2_1 = __uuidof(S2);
-  GUID s2_2 = __uuidof(S2);
 
-  // CHECK: store %struct._GUID* @_GUID_87654321_4321_4321_4321_ba0987654321, %struct._GUID** %r, align 4
+  // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_87654321_4321_4321_4321_ba0987654321 to %struct._GUID*), %struct._GUID** %r, align 4
   const GUID& r = __uuidof(S2);
-  // CHECK: store %struct._GUID* @_GUID_87654321_4321_4321_4321_ba0987654321, %struct._GUID** %p, align 4
+  // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_87654321_4321_4321_4321_ba0987654321 to %struct._GUID*), %struct._GUID** %p, align 4
   const GUID* p = &__uuidof(S2);
 
   // Special case _uuidof(0), local scope version.
-  // CHECK: store %struct._GUID* @_GUID_00000000_0000_0000_0000_000000000000, %struct._GUID** %zeroiid, align 4
+  // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_00000000_0000_0000_0000_000000000000 to %struct._GUID*), %struct._GUID** %zeroiid, align 4
   const GUID& zeroiid = __uuidof(0);
 }





More information about the cfe-commits mailing list