This is an archive of the discontinued LLVM Phabricator instance.

Rework how UuidAttr, CXXUuidofExpr, and GUID template arguments and constants are represented.
ClosedPublic

Authored by rsmith on Apr 14 2020, 5:13 PM.

Details

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.

Diff Detail

Event Timeline

rsmith created this revision.Apr 14 2020, 5:13 PM

There are a few cleanups I made along the way here that I'll be factoring out and committing separately.

rnk accepted this revision.Apr 14 2020, 5:43 PM

lgtm

There's a lot of stuff going on here, and I didn't review that deeply. Let me know if you want a closer reading of the code.

clang/include/clang/AST/TemplateBase.h
85–86

I think this is worth doing just to remove this special case.

clang/lib/AST/Decl.cpp
897–898

I suppose the answer is yes, it can be hidden. One cannot write a Windows app that expects &__uuidof(Foo) to be the same across DSOs. Hopefully we don't have to aim for compatibility to some compiler that targets ELF and supports uuids.

clang/lib/Sema/SemaExpr.cpp
3278

Weird things in the compiler never cease to surprise me.

This revision is now accepted and ready to land.Apr 14 2020, 5:43 PM
rsmith marked an inline comment as done.Apr 15 2020, 12:38 PM
rsmith added inline comments.
clang/lib/AST/Decl.cpp
897–898

I've not made this change for now. The patch as-is matches our former behavior, and it's far from obvious to me whether

template<const GUID&> void f() {}
f<__uuidof(x)>();

... should create a template instantiation with hidden visibility. For what it's worth, the variables we create for these GUID objects are dso_local and linkonce_odr but not hidden, which seems a little fishy to me. (We expose the symbol to other DSOs but never consume the symbol from other DSOs.) We could probably argue that that's "morally hidden"?

This is certainly easy to change if we think using default visibility is wrong.

This revision was automatically updated to reflect the committed changes.