2017-05-06 01:05:56 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -Wno-deprecated-declarations
|
2018-05-17 23:26:37 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify -fms-extensions %s -Wno-deprecated-declarations
|
2016-09-14 02:55:26 +08:00
|
|
|
|
|
|
|
typedef struct _GUID {
|
Rework how UuidAttr, CXXUuidofExpr, and GUID template arguments and constants are represented.
Summary:
Previously, we treated CXXUuidofExpr as quite a special case: it was the
only kind of expression that could be a canonical template argument, it
could be a constant lvalue base object, and so on. In addition, we
represented the UUID value as a string, whose source form we did not
preserve faithfully, and that we partially parsed in multiple different
places.
With this patch, we create an MSGuidDecl object to represent the
implicit object of type 'struct _GUID' created by a UuidAttr. Each
UuidAttr holds a pointer to its 'struct _GUID' and its original
(as-written) UUID string. A non-value-dependent CXXUuidofExpr behaves
like a DeclRefExpr denoting that MSGuidDecl object. We cache an APValue
representation of the GUID on the MSGuidDecl and use it from constant
evaluation where needed.
This allows removing a lot of the special-case logic to handle these
expressions. Unfortunately, many parts of Clang assume there are only
a couple of interesting kinds of ValueDecl, so the total amount of
special-case logic is not really reduced very much.
This fixes a few bugs and issues:
* PR38490: we now support reading from GUID objects returned from
__uuidof during constant evaluation.
* Our Itanium mangling for a non-instantiation-dependent template
argument involving __uuidof no longer depends on which CXXUuidofExpr
template argument we happened to see first.
* We now predeclare ::_GUID, and permit use of __uuidof without
any header inclusion, better matching MSVC's behavior. We do not
predefine ::__s_GUID, though; that seems like a step too far.
* Our IR representation for GUID constants now uses the correct IR type
wherever possible. We will still fall back to using the
{i32, i16, i16, [8 x i8]}
layout if a definition of struct _GUID is not available. This is not
ideal: in principle the two layouts could have different padding.
Reviewers: rnk, jdoerfert
Subscribers: arphaman, cfe-commits, aeubanks
Tags: #clang
Differential Revision: https://reviews.llvm.org/D78171
2020-04-12 13:15:29 +08:00
|
|
|
__UINT32_TYPE__ Data1;
|
|
|
|
__UINT16_TYPE__ Data2;
|
|
|
|
__UINT16_TYPE__ Data3;
|
|
|
|
__UINT8_TYPE__ Data4[8];
|
2016-09-14 02:55:26 +08:00
|
|
|
} GUID;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// cl.exe's behavior with merging uuid attributes is a bit erratic:
|
|
|
|
// * In []-style attributes, a single [] list must not list a duplicate uuid
|
|
|
|
// (even if it's the same uuid), and only a single declaration of a class
|
|
|
|
// must have a uuid else the compiler errors out (even if two declarations of
|
|
|
|
// a class have the same uuid).
|
|
|
|
// * For __declspec(uuid(...)), it's ok if several declarations of a class have
|
|
|
|
// an uuid, as long as it's the same uuid each time. If uuids on declarations
|
|
|
|
// don't match, the compiler errors out.
|
|
|
|
// * If there are several __declspec(uuid(...))s on one declaration, the
|
|
|
|
// compiler only warns about this and uses the last uuid. It even warns if
|
|
|
|
// the uuids are the same.
|
|
|
|
|
|
|
|
// clang-cl implements the following simpler (but largely compatible) behavior
|
|
|
|
// instead:
|
|
|
|
// * [] and __declspec uuids have the same behavior.
|
2018-02-22 15:49:13 +08:00
|
|
|
// * If there are several uuids on a class (no matter if on the same decl or
|
2016-09-14 02:55:26 +08:00
|
|
|
// on several decls), it is an error if they don't match.
|
|
|
|
// * Having several uuids that match is ok.
|
|
|
|
|
|
|
|
// Both cl and clang-cl accept this:
|
|
|
|
class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C1;
|
2016-09-14 09:16:54 +08:00
|
|
|
class __declspec(uuid("000000a0-0000-0000-c000-000000000049")) C1;
|
|
|
|
class __declspec(uuid("{000000a0-0000-0000-C000-000000000049}")) C1;
|
2016-09-14 02:55:26 +08:00
|
|
|
class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C1 {};
|
|
|
|
|
|
|
|
// Both cl and clang-cl error out on this:
|
|
|
|
// expected-note@+1 2{{previous uuid specified here}}
|
|
|
|
class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C2;
|
|
|
|
// expected-error@+1 {{uuid does not match previous declaration}}
|
|
|
|
class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C2;
|
|
|
|
// expected-error@+1 {{uuid does not match previous declaration}}
|
|
|
|
class __declspec(uuid("220000A0-0000-0000-C000-000000000049")) C2 {};
|
|
|
|
|
|
|
|
// expected-note@+1 {{previous uuid specified here}}
|
|
|
|
class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C2_2;
|
|
|
|
class C2_2;
|
|
|
|
// expected-error@+1 {{uuid does not match previous declaration}}
|
|
|
|
class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C2_2;
|
|
|
|
|
|
|
|
// clang-cl accepts this, but cl errors out:
|
|
|
|
[uuid("000000A0-0000-0000-C000-000000000049")] class C3;
|
|
|
|
[uuid("000000A0-0000-0000-C000-000000000049")] class C3;
|
|
|
|
[uuid("000000A0-0000-0000-C000-000000000049")] class C3 {};
|
|
|
|
|
|
|
|
// Both cl and clang-cl error out on this (but for different reasons):
|
|
|
|
// expected-note@+1 2{{previous uuid specified here}}
|
|
|
|
[uuid("000000A0-0000-0000-C000-000000000049")] class C4;
|
|
|
|
// expected-error@+1 {{uuid does not match previous declaration}}
|
|
|
|
[uuid("110000A0-0000-0000-C000-000000000049")] class C4;
|
|
|
|
// expected-error@+1 {{uuid does not match previous declaration}}
|
|
|
|
[uuid("220000A0-0000-0000-C000-000000000049")] class C4 {};
|
|
|
|
|
|
|
|
// Both cl and clang-cl error out on this:
|
2018-06-26 04:06:13 +08:00
|
|
|
// expected-error@+1 {{uuid does not match previous declaration}}
|
2018-08-03 09:21:16 +08:00
|
|
|
class __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
|
|
|
|
// expected-note@+1 {{previous uuid specified here}}
|
2016-09-14 02:55:26 +08:00
|
|
|
__declspec(uuid("110000A0-0000-0000-C000-000000000049")) C5;
|
|
|
|
|
2018-06-26 04:06:13 +08:00
|
|
|
// expected-error@+1 {{uuid does not match previous declaration}}
|
2018-08-03 09:21:16 +08:00
|
|
|
[uuid("000000A0-0000-0000-C000-000000000049"),
|
|
|
|
// expected-note@+1 {{previous uuid specified here}}
|
2016-09-14 02:55:26 +08:00
|
|
|
uuid("110000A0-0000-0000-C000-000000000049")] class C6;
|
|
|
|
|
|
|
|
// cl doesn't diagnose having one uuid each as []-style attributes and as
|
|
|
|
// __declspec, even if the uuids differ. clang-cl errors if they differ.
|
|
|
|
[uuid("000000A0-0000-0000-C000-000000000049")]
|
|
|
|
class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C7;
|
|
|
|
|
|
|
|
// expected-note@+1 {{previous uuid specified here}}
|
|
|
|
[uuid("000000A0-0000-0000-C000-000000000049")]
|
|
|
|
// expected-error@+1 {{uuid does not match previous declaration}}
|
|
|
|
class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C8;
|
|
|
|
|
|
|
|
|
|
|
|
// cl warns on this, but clang-cl is fine with it (which is consistent with
|
|
|
|
// e.g. specifying __multiple_inheritance several times, which cl accepts
|
|
|
|
// without warning too).
|
|
|
|
class __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
|
|
|
|
__declspec(uuid("000000A0-0000-0000-C000-000000000049")) C9;
|
|
|
|
|
|
|
|
// cl errors out on this, but clang-cl is fine with it (to be consistent with
|
|
|
|
// the previous case).
|
|
|
|
[uuid("000000A0-0000-0000-C000-000000000049"),
|
|
|
|
uuid("000000A0-0000-0000-C000-000000000049")] class C10;
|
2018-05-17 23:26:37 +08:00
|
|
|
|
|
|
|
template <const GUID* p>
|
|
|
|
void F1() {
|
|
|
|
// Regression test for PR24986. The given GUID should just work as a pointer.
|
|
|
|
const GUID* q = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void F2() {
|
|
|
|
// The UUID should work for a non-type template parameter.
|
|
|
|
F1<&__uuidof(C1)>();
|
|
|
|
}
|
|
|
|
|
2016-09-14 02:55:26 +08:00
|
|
|
}
|
2019-12-29 05:06:13 +08:00
|
|
|
|
|
|
|
// Test class/struct redeclaration where the subsequent
|
|
|
|
// declaration has a uuid attribute
|
|
|
|
struct X{};
|
|
|
|
|
Rework how UuidAttr, CXXUuidofExpr, and GUID template arguments and constants are represented.
Summary:
Previously, we treated CXXUuidofExpr as quite a special case: it was the
only kind of expression that could be a canonical template argument, it
could be a constant lvalue base object, and so on. In addition, we
represented the UUID value as a string, whose source form we did not
preserve faithfully, and that we partially parsed in multiple different
places.
With this patch, we create an MSGuidDecl object to represent the
implicit object of type 'struct _GUID' created by a UuidAttr. Each
UuidAttr holds a pointer to its 'struct _GUID' and its original
(as-written) UUID string. A non-value-dependent CXXUuidofExpr behaves
like a DeclRefExpr denoting that MSGuidDecl object. We cache an APValue
representation of the GUID on the MSGuidDecl and use it from constant
evaluation where needed.
This allows removing a lot of the special-case logic to handle these
expressions. Unfortunately, many parts of Clang assume there are only
a couple of interesting kinds of ValueDecl, so the total amount of
special-case logic is not really reduced very much.
This fixes a few bugs and issues:
* PR38490: we now support reading from GUID objects returned from
__uuidof during constant evaluation.
* Our Itanium mangling for a non-instantiation-dependent template
argument involving __uuidof no longer depends on which CXXUuidofExpr
template argument we happened to see first.
* We now predeclare ::_GUID, and permit use of __uuidof without
any header inclusion, better matching MSVC's behavior. We do not
predefine ::__s_GUID, though; that seems like a step too far.
* Our IR representation for GUID constants now uses the correct IR type
wherever possible. We will still fall back to using the
{i32, i16, i16, [8 x i8]}
layout if a definition of struct _GUID is not available. This is not
ideal: in principle the two layouts could have different padding.
Reviewers: rnk, jdoerfert
Subscribers: arphaman, cfe-commits, aeubanks
Tags: #clang
Differential Revision: https://reviews.llvm.org/D78171
2020-04-12 13:15:29 +08:00
|
|
|
struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) X;
|
|
|
|
|
|
|
|
namespace ConstantEvaluation {
|
|
|
|
class __declspec(uuid("1babb1ed-feed-c01d-1ced-decafc0ffee5")) Request;
|
|
|
|
constexpr GUID a = __uuidof(Request);
|
|
|
|
static_assert(a.Data1 == 0x1babb1ed, "");
|
|
|
|
static_assert(__uuidof(Request).Data1 == 0x1babb1ed, "");
|
|
|
|
static_assert(a.Data2 == 0xfeed, "");
|
|
|
|
static_assert(__uuidof(Request).Data2 == 0xfeed, "");
|
|
|
|
static_assert(a.Data3 == 0xc01d, "");
|
|
|
|
static_assert(__uuidof(Request).Data3 == 0xc01d, "");
|
|
|
|
static_assert(a.Data4[0] == 0x1c, "");
|
|
|
|
static_assert(__uuidof(Request).Data4[0] == 0x1c, "");
|
|
|
|
static_assert(a.Data4[1] == 0xed, "");
|
|
|
|
static_assert(__uuidof(Request).Data4[1] == 0xed, "");
|
|
|
|
static_assert(a.Data4[2] == 0xde, "");
|
|
|
|
static_assert(__uuidof(Request).Data4[2] == 0xde, "");
|
|
|
|
static_assert(a.Data4[7] == 0xe5, "");
|
|
|
|
static_assert(__uuidof(Request).Data4[7] == 0xe5, "");
|
|
|
|
constexpr int k = __uuidof(Request).Data4[8]; // expected-error {{constant expression}} expected-note {{past-the-end}}
|
|
|
|
}
|