]> granicus.if.org Git - clang/commitdiff
AST: __uuidof should leak through templated types
authorDavid Majnemer <david.majnemer@gmail.com>
Sat, 7 Sep 2013 06:59:46 +0000 (06:59 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Sat, 7 Sep 2013 06:59:46 +0000 (06:59 +0000)
Summary:
__uuidof on templated types should exmaine if any of its template
parameters have a uuid declspec.  If exactly one does, then take it.
Otherwise, issue an appropriate error.

Reviewers: rsmith, thakis, rnk

CC: cfe-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D1419

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190240 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ExprCXX.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/ExprCXX.cpp
lib/Sema/SemaExprCXX.cpp
test/Parser/MicrosoftExtensions.cpp

index 23c91742c709fa2407d6cdce9d367a8c1a6ab8d9..c39d29f80e1e88177d8d6cbc9fa4749ba1835d3f 100644 (file)
@@ -735,8 +735,10 @@ public:
     return T->getStmtClass() == CXXUuidofExprClass;
   }
 
-  /// Grabs __declspec(uuid()) off a type, or returns 0 if there is none.
-  static UuidAttr *GetUuidAttrOfType(QualType QT);
+  /// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to
+  /// a single GUID.
+  static UuidAttr *GetUuidAttrOfType(QualType QT,
+                                     bool *HasMultipleGUIDsPtr = 0);
 
   // Iterators
   child_range children() {
index 22a774b54b914f609181be777df3e77af598aa0d..59542f00715e2dbb32d802aa21b3f7e4c99e1705 100644 (file)
@@ -4858,6 +4858,8 @@ def err_need_header_before_ms_uuidof : Error<
   "you need to include <guiddef.h> before using the '__uuidof' operator">;
 def err_uuidof_without_guid : Error<
   "cannot call operator __uuidof on a type with no GUID">;
+def err_uuidof_with_multiple_guids : Error<
+  "cannot call operator __uuidof on a type with multiple GUIDs">;
 def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">;
 def err_static_illegal_in_new : Error<
   "the 'static' modifier for the array size is not legal in new expressions">;
index 7f1a287d1facb5a855ce80b91880f0ae92a6b81e..d87c60a733b1c9f321e871736fbcea0772972c3b 100644 (file)
@@ -53,7 +53,8 @@ QualType CXXUuidofExpr::getTypeOperand() const {
 }
 
 // static
-UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
+UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT,
+                                           bool *RDHasMultipleGUIDsPtr) {
   // Optionally remove one level of pointer, reference or array indirection.
   const Type *Ty = QT.getTypePtr();
   if (QT->isPointerType() || QT->isReferenceType())
@@ -63,11 +64,51 @@ UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
 
   // Loop all record redeclaration looking for an uuid attribute.
   CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
-  for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
-       E = RD->redecls_end(); I != E; ++I) {
-    if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
-      return Uuid;
-  }
+  if (!RD)
+    return 0;
+
+  if (ClassTemplateSpecializationDecl *CTSD =
+          dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+    const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+    UuidAttr *UuidForRD = 0;
+
+    for (unsigned I = 0, N = TAL.size(); I != N; ++I) {
+      const TemplateArgument &TA = TAL[I];
+      bool SeenMultipleGUIDs = false;
+
+      UuidAttr *UuidForTA = 0;
+      if (TA.getKind() == TemplateArgument::Type)
+        UuidForTA = GetUuidAttrOfType(TA.getAsType(), &SeenMultipleGUIDs);
+      else if (TA.getKind() == TemplateArgument::Declaration)
+        UuidForTA =
+            GetUuidAttrOfType(TA.getAsDecl()->getType(), &SeenMultipleGUIDs);
+
+      // If the template argument has a UUID, there are three cases:
+      //  - This is the first UUID seen for this RecordDecl.
+      //  - This is a different UUID than previously seed for this RecordDecl.
+      //  - This is the same UUID than previously seed for this RecordDecl.
+      if (UuidForTA) {
+        if (!UuidForRD)
+          UuidForRD = UuidForTA;
+        else if (UuidForRD != UuidForTA)
+          SeenMultipleGUIDs = true;
+      }
+
+      // Seeing multiple UUIDs means that we couldn't find a UUID
+      if (SeenMultipleGUIDs) {
+        if (RDHasMultipleGUIDsPtr)
+          *RDHasMultipleGUIDsPtr = true;
+        return 0;
+      }
+    }
+
+    return UuidForRD;
+  } else
+    for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
+                                        E = RD->redecls_end();
+         I != E; ++I)
+      if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
+        return Uuid;
 
   return 0;
 }
index 0b58a3d86d8a55d35d81c08caf1ccdda41c98595..72bbfbc7268da565daf9624cde1686da28b9779d 100644 (file)
@@ -462,11 +462,16 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
                                 TypeSourceInfo *Operand,
                                 SourceLocation RParenLoc) {
   if (!Operand->getType()->isDependentType()) {
-    if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType()))
-      return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+    bool HasMultipleGUIDs = false;
+    if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType(),
+                                          &HasMultipleGUIDs)) {
+      if (HasMultipleGUIDs)
+        return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
+      else
+        return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+    }
   }
 
-  // FIXME: add __uuidof semantic analysis for type operand.
   return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(),
                                            Operand,
                                            SourceRange(TypeidLoc, RParenLoc)));
@@ -478,11 +483,16 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
                                 Expr *E,
                                 SourceLocation RParenLoc) {
   if (!E->getType()->isDependentType()) {
-    if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType()) &&
-        !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
-      return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+    bool HasMultipleGUIDs = false;
+    if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType(), &HasMultipleGUIDs) &&
+        !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
+      if (HasMultipleGUIDs)
+        return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
+      else
+        return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+    }
   }
-  // FIXME: add __uuidof semantic analysis for type operand.
+
   return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(),
                                            E,
                                            SourceRange(TypeidLoc, RParenLoc)));
index c2d749a288fc84e5f110940639822da74b5217ff..ef873d6430604d31d453c084d8415bf0e5bbade2 100644 (file)
@@ -116,6 +116,25 @@ COM_CLASS_TEMPLATE_REF<int, __uuidof(struct_with_uuid)> good_template_arg;
 
 COM_CLASS_TEMPLATE<int, __uuidof(struct_with_uuid)> bad_template_arg; // expected-error {{non-type template argument of type 'const _GUID' is not a constant expression}}
 
+namespace PR16911 {
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid;
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid2;
+
+template <typename T, typename T2>
+struct thing {
+};
+
+struct empty {};
+struct inher : public thing<empty, uuid2> {};
+
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid;
+const struct _GUID *w = &__uuidof(inher); // expected-error{{cannot call operator __uuidof on a type with no GUID}}
+const struct _GUID *x = &__uuidof(thing<uuid, inher>);
+const struct _GUID *y = &__uuidof(thing<uuid2, uuid>); // expected-error{{cannot call operator __uuidof on a type with multiple GUIDs}}
+thing<uuid2, uuid> thing_obj = thing<uuid2, uuid>();
+const struct _GUID *z = &__uuidof(thing_obj); // expected-error{{cannot call operator __uuidof on a type with multiple GUIDs}}
+}
+
 class CtorCall {
 public:
   CtorCall& operator=(const CtorCall& that);