[cfe-commits] r162067 - in /cfe/trunk: docs/ include/clang/Basic/ include/clang/Parse/ include/clang/Sema/ lib/Parse/ lib/Sema/ test/Sema/

Dmitri Gribenko gribozavr at gmail.com
Thu Aug 16 17:08:38 PDT 2012


Author: gribozavr
Date: Thu Aug 16 19:08:38 2012
New Revision: 162067

URL: http://llvm.org/viewvc/llvm-project?rev=162067&view=rev
Log:
Add support for "type safety" attributes that allow checking that 'void *'
function arguments and arguments for variadic functions are of a particular
type which is determined by some other argument to the same function call.

Usecases include:
* MPI library implementations, where these attributes enable checking that
  buffer type matches the passed MPI_Datatype;
* for HDF5 library there is a similar usecase as MPI;
* checking types of variadic functions' arguments for functions like
  fcntl() and ioctl().

Added:
    cfe/trunk/test/Sema/warn-type-safety-mpi-hdf5.c
    cfe/trunk/test/Sema/warn-type-safety.c
    cfe/trunk/test/Sema/warn-type-safety.cpp
Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Sema/AttributeList.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/test/Sema/128bitint.c

Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Thu Aug 16 19:08:38 2012
@@ -142,6 +142,13 @@
     <li><a href="#ts_slr"><tt>shared_locks_required(...)</tt></a></li>   
     </ul>
 </li>
+<li><a href="#type_safety">Type Safety Checking</a>
+  <ul>
+  <li><a href="#argument_with_type_tag"><tt>argument_with_type_tag(...)</tt></a></li>
+  <li><a href="#pointer_with_type_tag"><tt>pointer_with_type_tag(...)</tt></a></li>
+  <li><a href="#type_tag_for_datatype"><tt>type_tag_for_datatype(...)</tt></a></li>
+  </ul>
+</li>
 </ul>
 
 <!-- ======================================================================= -->
@@ -1913,6 +1920,161 @@
 shared locks. Arguments must be lockable type, and there must be at 
 least one argument.</p> 
 
+<!-- ======================================================================= -->
+<h2 id="type_safety">Type Safety Checking</h2>
+<!-- ======================================================================= -->
+
+<p>Clang supports additional attributes to enable checking type safety
+properties that can't be enforced by C type system.  Usecases include:</p>
+<ul>
+<li>MPI library implementations, where these attributes enable checking that
+    buffer type matches the passed <tt>MPI_Datatype</tt>;</li>
+<li>for HDF5 library there is a similar usecase as MPI;</li>
+<li>checking types of variadic functions' arguments for functions like
+    <tt>fcntl()</tt> and <tt>ioctl()</tt>.</li>
+</ul>
+
+<p>You can detect support for these attributes with __has_attribute().  For
+example:</p>
+
+<blockquote>
+<pre>
+#if defined(__has_attribute)
+#  if __has_attribute(argument_with_type_tag) && \
+      __has_attribute(pointer_with_type_tag) && \
+      __has_attribute(type_tag_for_datatype)
+#    define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx)))
+/* ... other macros ... */
+#  endif
+#endif
+
+#if !defined(ATTR_MPI_PWT)
+#define ATTR_MPI_PWT(buffer_idx, type_idx)
+#endif
+
+int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
+    ATTR_MPI_PWT(1,3);
+</pre>
+</blockquote>
+
+<h3 id="argument_with_type_tag"><tt>argument_with_type_tag(...)</tt></h3>
+
+<p>Use <tt>__attribute__((argument_with_type_tag(arg_kind, arg_idx,
+type_tag_idx)))</tt> on a function declaration to specify that the function
+accepts a type tag that determines the type of some other argument.
+<tt>arg_kind</tt> is an identifier that should be used when annotating all
+applicable type tags.</p>
+
+<p>This attribute is primarily useful for checking arguments of variadic
+functions (<tt>pointer_with_type_tag</tt> can be used in most of non-variadic
+cases).</p>
+
+<p>For example:</p>
+<blockquote>
+<pre>
+int fcntl(int fd, int cmd, ...)
+      __attribute__(( argument_with_type_tag(fcntl,3,2) ));
+</pre>
+</blockquote>
+
+<h3 id="pointer_with_type_tag"><tt>pointer_with_type_tag(...)</tt></h3>
+
+<p>Use <tt>__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx,
+type_tag_idx)))</tt> on a function declaration to specify that the
+function a type tag that determines the pointee type of some other pointer
+argument.</p>
+
+<p>For example:</p>
+<blockquote>
+<pre>
+int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
+    __attribute__(( pointer_with_type_tag(mpi,1,3) ));
+</pre>
+</blockquote>
+
+<h3 id="type_tag_for_datatype"><tt>type_tag_for_datatype(...)</tt></h3>
+
+<p>Clang supports annotating type tags of two forms.</p>
+
+<ul>
+<li><b>Type tag that is an expression containing a reference to some declared
+identifier.</b> Use <tt>__attribute__((type_tag_for_datatype(kind, type)))</tt>
+on a declaration with that identifier:
+
+<blockquote>
+<pre>
+extern struct mpi_datatype mpi_datatype_int
+    __attribute__(( type_tag_for_datatype(mpi,int) ));
+#define MPI_INT ((MPI_Datatype) &mpi_datatype_int)
+</pre>
+</blockquote></li>
+
+<li><b>Type tag that is an integral literal.</b>  Introduce a <tt>static
+const</tt> variable with a corresponding initializer value and attach
+<tt>__attribute__((type_tag_for_datatype(kind, type)))</tt> on that
+declaration, for example:
+
+<blockquote>
+<pre>
+#define MPI_INT ((MPI_Datatype) 42)
+static const MPI_Datatype mpi_datatype_int
+    __attribute__(( type_tag_for_datatype(mpi,int) )) = 42
+</pre>
+</blockquote></li>
+</ul>
+
+<p>The attribute also accepts an optional third argument that determines how
+the expression is compared to the type tag.  There are two supported flags:</p>
+
+<ul><li><tt>layout_compatible</tt> will cause types to be compared according to
+layout-compatibility rules (C++11 [class.mem] p 17, 18).  This is
+implemented to support annotating types like <tt>MPI_DOUBLE_INT</tt>.
+
+<p>For example:</p>
+<blockquote>
+<pre>
+/* In mpi.h */
+struct internal_mpi_double_int { double d; int i; };
+extern struct mpi_datatype mpi_datatype_double_int
+    __attribute__(( type_tag_for_datatype(mpi, struct internal_mpi_double_int,
+                                          layout_compatible) ));
+
+#define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int)
+
+/* In user code */
+struct my_pair { double a; int b; };
+struct my_pair *buffer;
+MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning
+
+struct my_int_pair { int a; int b; }
+struct my_int_pair *buffer2;
+MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning: actual buffer element
+                                                 // type 'struct my_int_pair'
+                                                 // doesn't match specified MPI_Datatype
+</pre>
+</blockquote>
+</li>
+
+<li><tt>must_be_null</tt> specifies that the expression should be a null
+pointer constant, for example:
+
+<blockquote>
+<pre>
+/* In mpi.h */
+extern struct mpi_datatype mpi_datatype_null
+    __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) ));
+
+#define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null)
+
+/* In user code */
+MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL
+                                                   // was specified but buffer
+                                                   // is not a null pointer
+</pre>
+</blockquote>
+</li>
+</ul>
+
 </div>
 </body>
 </html>

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Aug 16 19:08:38 2012
@@ -826,6 +826,27 @@
   let TemplateDependent = 1;
 }
 
+// Type safety attributes for `void *' pointers and type tags.
+
+def ArgumentWithTypeTag : InheritableAttr {
+  let Spellings = [GNU<"argument_with_type_tag">,
+                   GNU<"pointer_with_type_tag">];
+  let Args = [IdentifierArgument<"ArgumentKind">,
+              UnsignedArgument<"ArgumentIdx">,
+              UnsignedArgument<"TypeTagIdx">,
+              BoolArgument<"IsPointer">];
+  let Subjects = [Function];
+}
+
+def TypeTagForDatatype : InheritableAttr {
+  let Spellings = [GNU<"type_tag_for_datatype">];
+  let Args = [IdentifierArgument<"ArgumentKind">,
+              TypeArgument<"MatchingCType">,
+              BoolArgument<"LayoutCompatible">,
+              BoolArgument<"MustBeNull">];
+  let Subjects = [Var];
+}
+
 // Microsoft-related attributes
 
 def MsStruct : InheritableAttr {

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu Aug 16 19:08:38 2012
@@ -343,6 +343,8 @@
 def Format2 : DiagGroup<"format=2",
                         [FormatNonLiteral, FormatSecurity, FormatY2K]>;
 
+def TypeSafety : DiagGroup<"type-safety">;
+
 def Extra : DiagGroup<"extra", [
     MissingFieldInitializers,
     IgnoredQualifiers,

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu Aug 16 19:08:38 2012
@@ -677,6 +677,10 @@
   "'unavailable' availability overrides all other availability information">,
   InGroup<Availability>;
 
+// Type safety attributes
+def err_type_safety_unknown_flag : Error<
+  "invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">;
+
 // Language specific pragmas
 // - Generic warnings
 def warn_pragma_expected_lparen : Warning<

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Aug 16 19:08:38 2012
@@ -1547,6 +1547,8 @@
   "'%0' attribute requires parameter %1 to be an integer constant">;
 def err_attribute_argument_n_not_string : Error<
   "'%0' attribute requires parameter %1 to be a string">;
+def err_attribute_argument_n_not_identifier : Error<
+  "'%0' attribute requires parameter %1 to be an identifier">;
 def err_attribute_argument_out_of_bounds : Error<
   "'%0' attribute parameter %1 is out of bounds">;
 def err_attribute_requires_objc_interface : Error<
@@ -1555,6 +1557,8 @@
   "uuid attribute contains a malformed GUID">;
 def warn_nonnull_pointers_only : Warning<
   "nonnull attribute only applies to pointer arguments">;
+def err_attribute_pointers_only : Error<
+  "'%0' attribute only applies to pointer arguments">;
 def err_attribute_invalid_implicit_this_argument : Error<
   "'%0' attribute is invalid for the implicit this argument">;
 def err_ownership_type : Error<
@@ -1770,7 +1774,6 @@
 def warn_attribute_not_on_decl : Error<
   "%0 attribute ignored when parsing type">;
 
-
 // Availability attribute
 def warn_availability_unknown_platform : Warning<
   "unknown platform %0 in availability macro">, InGroup<Availability>;
@@ -5479,6 +5482,23 @@
   "assigning %select{field|instance variable}0 to itself">,
   InGroup<SelfAssignmentField>;
 
+// Type safety attributes
+def err_type_tag_for_datatype_not_ice : Error<
+  "'type_tag_for_datatype' attribute requires the initializer to be "
+  "an %select{integer|integral}0 constant expression">;
+def err_type_tag_for_datatype_too_large : Error<
+  "'type_tag_for_datatype' attribute requires the initializer to be "
+  "an %select{integer|integral}0 constant expression "
+  "that can be represented by a 64 bit integer">;
+def warn_type_tag_for_datatype_wrong_kind : Warning<
+  "this type tag was not designed to be used with this function">,
+  InGroup<TypeSafety>;
+def warn_type_safety_type_mismatch : Warning<
+  "argument type %0 doesn't match specified '%1' type tag "
+  "%select{that requires %3|}2">, InGroup<TypeSafety>;
+def warn_type_safety_null_pointer_required : Warning<
+  "specified %0 type tag requires a null pointer">, InGroup<TypeSafety>;
+
 // Generic selections.
 def err_assoc_type_incomplete : Error<
   "type %0 in generic association incomplete">;

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Thu Aug 16 19:08:38 2012
@@ -1834,6 +1834,10 @@
                                   ParsedAttributes &Attrs,
                                   SourceLocation *EndLoc);
 
+  void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
+                                        SourceLocation AttrNameLoc,
+                                        ParsedAttributes &Attrs,
+                                        SourceLocation *EndLoc);
 
   void ParseTypeofSpecifier(DeclSpec &DS);
   SourceLocation ParseDecltypeSpecifier(DeclSpec &DS);

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Thu Aug 16 19:08:38 2012
@@ -19,6 +19,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/VersionTuple.h"
+#include "clang/Sema/Ownership.h"
 #include <cassert>
 
 namespace clang {
@@ -87,6 +88,10 @@
   /// availability attribute.
   unsigned IsAvailability : 1;
 
+  /// True if this has extra information associated with a
+  /// type_tag_for_datatype attribute.
+  unsigned IsTypeTagForDatatype : 1;
+
   unsigned AttrKind : 8;
 
   /// \brief The location of the 'unavailable' keyword in an
@@ -119,6 +124,22 @@
     return reinterpret_cast<const AvailabilityChange*>(this+1)[index];
   }
 
+public:
+  struct TypeTagForDatatypeData {
+    ParsedType *MatchingCType;
+    unsigned LayoutCompatible : 1;
+    unsigned MustBeNull : 1;
+  };
+
+private:
+  TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() {
+    return *reinterpret_cast<TypeTagForDatatypeData *>(this + 1);
+  }
+
+  const TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() const {
+    return *reinterpret_cast<const TypeTagForDatatypeData *>(this + 1);
+  }
+
   AttributeList(const AttributeList &); // DO NOT IMPLEMENT
   void operator=(const AttributeList &); // DO NOT IMPLEMENT
   void operator delete(void *); // DO NOT IMPLEMENT
@@ -126,6 +147,7 @@
 
   size_t allocated_size() const;
 
+  /// Constructor for attributes with expression arguments.
   AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
                 IdentifierInfo *scopeName, SourceLocation scopeLoc,
                 IdentifierInfo *parmName, SourceLocation parmLoc,
@@ -134,12 +156,13 @@
     : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
       AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
       NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false),
-      UsedAsTypeAttr(false), IsAvailability(false), 
-      NextInPosition(0), NextInPool(0) {
+      UsedAsTypeAttr(false), IsAvailability(false),
+      IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) {
     if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*));
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
 
+  /// Constructor for availability attributes.
   AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
                 IdentifierInfo *scopeName, SourceLocation scopeLoc,
                 IdentifierInfo *parmName, SourceLocation parmLoc,
@@ -153,6 +176,7 @@
       AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
       NumArgs(0), SyntaxUsed(syntaxUsed),
       Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
+      IsTypeTagForDatatype(false),
       UnavailableLoc(unavailable), MessageExpr(messageExpr),
       NextInPosition(0), NextInPool(0) {
     new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
@@ -161,6 +185,25 @@
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
 
+  /// Constructor for type_tag_for_datatype attribute.
+  AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
+                IdentifierInfo *scopeName, SourceLocation scopeLoc,
+                IdentifierInfo *argumentKindName,
+                SourceLocation argumentKindLoc,
+                ParsedType matchingCType, bool layoutCompatible,
+                bool mustBeNull, Syntax syntaxUsed)
+    : AttrName(attrName), ScopeName(scopeName), ParmName(argumentKindName),
+      AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(argumentKindLoc),
+      NumArgs(0), SyntaxUsed(syntaxUsed),
+      Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
+      IsTypeTagForDatatype(true), NextInPosition(NULL), NextInPool(NULL) {
+    TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
+    new (&ExtraData.MatchingCType) ParsedType(matchingCType);
+    ExtraData.LayoutCompatible = layoutCompatible;
+    ExtraData.MustBeNull = mustBeNull;
+    AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
+  }
+
   friend class AttributePool;
   friend class AttributeFactory;
 
@@ -279,6 +322,24 @@
     assert(getKind() == AT_Availability && "Not an availability attribute");
     return MessageExpr;
   }
+
+  const ParsedType &getMatchingCType() const {
+    assert(getKind() == AT_TypeTagForDatatype &&
+           "Not a type_tag_for_datatype attribute");
+    return *getTypeTagForDatatypeDataSlot().MatchingCType;
+  }
+
+  bool getLayoutCompatible() const {
+    assert(getKind() == AT_TypeTagForDatatype &&
+           "Not a type_tag_for_datatype attribute");
+    return getTypeTagForDatatypeDataSlot().LayoutCompatible;
+  }
+
+  bool getMustBeNull() const {
+    assert(getKind() == AT_TypeTagForDatatype &&
+           "Not a type_tag_for_datatype attribute");
+    return getTypeTagForDatatypeDataSlot().MustBeNull;
+  }
 };
 
 /// A factory, from which one makes pools, from which one creates
@@ -294,7 +355,11 @@
     AvailabilityAllocSize =
       sizeof(AttributeList)
       + ((3 * sizeof(AvailabilityChange) + sizeof(void*) - 1)
-         / sizeof(void*) * sizeof(void*))
+         / sizeof(void*) * sizeof(void*)),
+    TypeTagForDatatypeAllocSize =
+      sizeof(AttributeList)
+      + (sizeof(AttributeList::TypeTagForDatatypeData) + sizeof(void *) - 1)
+        / sizeof(void*) * sizeof(void*)
   };
 
 private:
@@ -411,6 +476,21 @@
 
   AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
                                         SourceLocation TokLoc, int Arg);
+
+  AttributeList *createTypeTagForDatatype(
+                    IdentifierInfo *attrName, SourceRange attrRange,
+                    IdentifierInfo *scopeName, SourceLocation scopeLoc,
+                    IdentifierInfo *argumentKindName,
+                    SourceLocation argumentKindLoc,
+                    ParsedType matchingCType, bool layoutCompatible,
+                    bool mustBeNull, AttributeList::Syntax syntax) {
+    void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize);
+    return add(new (memory) AttributeList(attrName, attrRange,
+                                          scopeName, scopeLoc,
+                                          argumentKindName, argumentKindLoc,
+                                          matchingCType, layoutCompatible,
+                                          mustBeNull, syntax));
+  }
 };
 
 /// addAttributeLists - Add two AttributeLists together
@@ -503,7 +583,7 @@
   /// dependencies on this method, it may not be long-lived.
   AttributeList *&getListRef() { return list; }
 
-
+  /// Add attribute with expression arguments.
   AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange,
                         IdentifierInfo *scopeName, SourceLocation scopeLoc,
                         IdentifierInfo *parmName, SourceLocation parmLoc,
@@ -516,6 +596,7 @@
     return attr;
   }
 
+  /// Add availability attribute.
   AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange,
                         IdentifierInfo *scopeName, SourceLocation scopeLoc,
                         IdentifierInfo *parmName, SourceLocation parmLoc,
@@ -533,6 +614,24 @@
     return attr;
   }
 
+  /// Add type_tag_for_datatype attribute.
+  AttributeList *addNewTypeTagForDatatype(
+                        IdentifierInfo *attrName, SourceRange attrRange,
+                        IdentifierInfo *scopeName, SourceLocation scopeLoc,
+                        IdentifierInfo *argumentKindName,
+                        SourceLocation argumentKindLoc,
+                        ParsedType matchingCType, bool layoutCompatible,
+                        bool mustBeNull, AttributeList::Syntax syntax) {
+    AttributeList *attr =
+      pool.createTypeTagForDatatype(attrName, attrRange,
+                                    scopeName, scopeLoc,
+                                    argumentKindName, argumentKindLoc,
+                                    matchingCType, layoutCompatible,
+                                    mustBeNull, syntax);
+    add(attr);
+    return attr;
+  }
+
   AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name,
                                SourceLocation loc, int arg) {
     AttributeList *attr =

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Aug 16 19:08:38 2012
@@ -7145,6 +7145,42 @@
   void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field,
                                    Expr *Init);
 
+public:
+  /// \brief Register a magic integral constant to be used as a type tag.
+  void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
+                                  uint64_t MagicValue, QualType Type,
+                                  bool LayoutCompatible, bool MustBeNull);
+
+  struct TypeTagData {
+    TypeTagData() {}
+
+    TypeTagData(QualType Type, bool LayoutCompatible, bool MustBeNull) :
+        Type(Type), LayoutCompatible(LayoutCompatible),
+        MustBeNull(MustBeNull)
+    {}
+
+    QualType Type;
+
+    /// If true, \c Type should be compared with other expression's types for
+    /// layout-compatibility.
+    unsigned LayoutCompatible : 1;
+    unsigned MustBeNull : 1;
+  };
+
+  /// A pair of ArgumentKind identifier and magic value.  This uniquely
+  /// identifies the magic value.
+  typedef std::pair<const IdentifierInfo *, uint64_t> TypeTagMagicValue;
+
+private:
+  /// \brief A map from magic value to type information.
+  OwningPtr<llvm::DenseMap<TypeTagMagicValue, TypeTagData> >
+      TypeTagForDatatypeMagicValues;
+
+  /// \brief Peform checks on a call of a function with argument_with_type_tag
+  /// or pointer_with_type_tag attributes.
+  void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
+                                const Expr * const *ExprArgs);
+
   /// \brief The parser's current scope.
   ///
   /// The parser maintains this state here.

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Aug 16 19:08:38 2012
@@ -68,7 +68,6 @@
         .Default(false);
 }
 
-
 /// ParseGNUAttributes - Parse a non-empty attributes list.
 ///
 /// [GNU] attributes:
@@ -193,6 +192,11 @@
     ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
     return;
   }
+  // Type safety attributes have their own grammar.
+  if (AttrName->isStr("type_tag_for_datatype")) {
+    ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
+    return;
+  }
 
   ConsumeParen(); // ignore the left paren loc for now
 
@@ -1020,6 +1024,70 @@
     *EndLoc = T.getCloseLocation();
 }
 
+void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
+                                              SourceLocation AttrNameLoc,
+                                              ParsedAttributes &Attrs,
+                                              SourceLocation *EndLoc) {
+  assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
+
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  T.consumeOpen();
+
+  if (Tok.isNot(tok::identifier)) {
+    Diag(Tok, diag::err_expected_ident);
+    T.skipToEnd();
+    return;
+  }
+  IdentifierInfo *ArgumentKind = Tok.getIdentifierInfo();
+  SourceLocation ArgumentKindLoc = ConsumeToken();
+
+  if (Tok.isNot(tok::comma)) {
+    Diag(Tok, diag::err_expected_comma);
+    T.skipToEnd();
+    return;
+  }
+  ConsumeToken();
+
+  SourceRange MatchingCTypeRange;
+  TypeResult MatchingCType = ParseTypeName(&MatchingCTypeRange);
+  if (MatchingCType.isInvalid()) {
+    T.skipToEnd();
+    return;
+  }
+
+  bool LayoutCompatible = false;
+  bool MustBeNull = false;
+  while (Tok.is(tok::comma)) {
+    ConsumeToken();
+    if (Tok.isNot(tok::identifier)) {
+      Diag(Tok, diag::err_expected_ident);
+      T.skipToEnd();
+      return;
+    }
+    IdentifierInfo *Flag = Tok.getIdentifierInfo();
+    if (Flag->isStr("layout_compatible"))
+      LayoutCompatible = true;
+    else if (Flag->isStr("must_be_null"))
+      MustBeNull = true;
+    else {
+      Diag(Tok, diag::err_type_safety_unknown_flag) << Flag;
+      T.skipToEnd();
+      return;
+    }
+    ConsumeToken(); // consume flag
+  }
+
+  if (!T.consumeClose()) {
+    Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, 0, AttrNameLoc,
+                                   ArgumentKind, ArgumentKindLoc,
+                                   MatchingCType.release(), LayoutCompatible,
+                                   MustBeNull, AttributeList::AS_GNU);
+  }
+
+  if (EndLoc)
+    *EndLoc = T.getCloseLocation();
+}
+
 /// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets
 /// of a C++11 attribute-specifier in a location where an attribute is not
 /// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this

Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Thu Aug 16 19:08:38 2012
@@ -21,6 +21,8 @@
 
 size_t AttributeList::allocated_size() const {
   if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
+  else if (IsTypeTagForDatatype)
+    return AttributeFactory::TypeTagForDatatypeAllocSize;
   return (sizeof(AttributeList) + NumArgs * sizeof(Expr*));
 }
 

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Aug 16 19:08:38 2012
@@ -513,6 +513,13 @@
          I = FDecl->specific_attr_begin<NonNullAttr>(),
          E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
     CheckNonNullArguments(*I, Args, Loc);
+
+  // Type safety checking.
+  for (specific_attr_iterator<ArgumentWithTypeTagAttr>
+         i = FDecl->specific_attr_begin<ArgumentWithTypeTagAttr>(),
+         e = FDecl->specific_attr_end<ArgumentWithTypeTagAttr>(); i != e; ++i) {
+    CheckArgumentWithTypeTag(*i, Args);
+  }
 }
 
 /// CheckConstructorCall - Check a constructor call for correctness and safety
@@ -5468,3 +5475,410 @@
     Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
   }
 }
+
+//===--- Layout compatibility ----------------------------------------------//
+
+namespace {
+
+bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2);
+
+/// \brief Check if two enumeration types are layout-compatible.
+bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) {
+  // C++11 [dcl.enum] p8:
+  // Two enumeration types are layout-compatible if they have the same
+  // underlying type.
+  return ED1->isComplete() && ED2->isComplete() &&
+         C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType());
+}
+
+/// \brief Check if two fields are layout-compatible.
+bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) {
+  if (!isLayoutCompatible(C, Field1->getType(), Field2->getType()))
+    return false;
+
+  if (Field1->isBitField() != Field2->isBitField())
+    return false;
+
+  if (Field1->isBitField()) {
+    // Make sure that the bit-fields are the same length.
+    unsigned Bits1 = Field1->getBitWidthValue(C);
+    unsigned Bits2 = Field2->getBitWidthValue(C);
+
+    if (Bits1 != Bits2)
+      return false;
+  }
+
+  return true;
+}
+
+/// \brief Check if two standard-layout structs are layout-compatible.
+/// (C++11 [class.mem] p17)
+bool isLayoutCompatibleStruct(ASTContext &C,
+                              RecordDecl *RD1,
+                              RecordDecl *RD2) {
+  // If both records are C++ classes, check that base classes match.
+  if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1)) {
+    // If one of records is a CXXRecordDecl we are in C++ mode,
+    // thus the other one is a CXXRecordDecl, too.
+    const CXXRecordDecl *D2CXX = cast<CXXRecordDecl>(RD2);
+    // Check number of base classes.
+    if (D1CXX->getNumBases() != D2CXX->getNumBases())
+      return false;
+
+    // Check the base classes.
+    for (CXXRecordDecl::base_class_const_iterator
+               Base1 = D1CXX->bases_begin(),
+           BaseEnd1 = D1CXX->bases_end(),
+              Base2 = D2CXX->bases_begin();
+         Base1 != BaseEnd1;
+         ++Base1, ++Base2) {
+      if (!isLayoutCompatible(C, Base1->getType(), Base2->getType()))
+        return false;
+    }
+  } else if (const CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(RD2)) {
+    // If only RD2 is a C++ class, it should have zero base classes.
+    if (D2CXX->getNumBases() > 0)
+      return false;
+  }
+
+  // Check the fields.
+  RecordDecl::field_iterator Field2 = RD2->field_begin(),
+                             Field2End = RD2->field_end(),
+                             Field1 = RD1->field_begin(),
+                             Field1End = RD1->field_end();
+  for ( ; Field1 != Field1End && Field2 != Field2End; ++Field1, ++Field2) {
+    if (!isLayoutCompatible(C, *Field1, *Field2))
+      return false;
+  }
+  if (Field1 != Field1End || Field2 != Field2End)
+    return false;
+
+  return true;
+}
+
+/// \brief Check if two standard-layout unions are layout-compatible.
+/// (C++11 [class.mem] p18)
+bool isLayoutCompatibleUnion(ASTContext &C,
+                             RecordDecl *RD1,
+                             RecordDecl *RD2) {
+  llvm::SmallPtrSet<FieldDecl *, 8> UnmatchedFields;
+  for (RecordDecl::field_iterator Field2 = RD2->field_begin(),
+                                  Field2End = RD2->field_end();
+       Field2 != Field2End; ++Field2) {
+    UnmatchedFields.insert(*Field2);
+  }
+
+  for (RecordDecl::field_iterator Field1 = RD1->field_begin(),
+                                  Field1End = RD1->field_end();
+       Field1 != Field1End; ++Field1) {
+    llvm::SmallPtrSet<FieldDecl *, 8>::iterator
+        I = UnmatchedFields.begin(),
+        E = UnmatchedFields.end();
+
+    for ( ; I != E; ++I) {
+      if (isLayoutCompatible(C, *Field1, *I)) {
+        bool Result = UnmatchedFields.erase(*I);
+        (void) Result;
+        assert(Result);
+        break;
+      }
+    }
+    if (I == E)
+      return false;
+  }
+
+  return UnmatchedFields.empty();
+}
+
+bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) {
+  if (RD1->isUnion() != RD2->isUnion())
+    return false;
+
+  if (RD1->isUnion())
+    return isLayoutCompatibleUnion(C, RD1, RD2);
+  else
+    return isLayoutCompatibleStruct(C, RD1, RD2);
+}
+
+/// \brief Check if two types are layout-compatible in C++11 sense.
+bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
+  if (T1.isNull() || T2.isNull())
+    return false;
+
+  // C++11 [basic.types] p11:
+  // If two types T1 and T2 are the same type, then T1 and T2 are
+  // layout-compatible types.
+  if (C.hasSameType(T1, T2))
+    return true;
+
+  T1 = T1.getCanonicalType().getUnqualifiedType();
+  T2 = T2.getCanonicalType().getUnqualifiedType();
+
+  const Type::TypeClass TC1 = T1->getTypeClass();
+  const Type::TypeClass TC2 = T2->getTypeClass();
+
+  if (TC1 != TC2)
+    return false;
+
+  if (TC1 == Type::Enum) {
+    return isLayoutCompatible(C,
+                              cast<EnumType>(T1)->getDecl(),
+                              cast<EnumType>(T2)->getDecl());
+  } else if (TC1 == Type::Record) {
+    if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType())
+      return false;
+
+    return isLayoutCompatible(C,
+                              cast<RecordType>(T1)->getDecl(),
+                              cast<RecordType>(T2)->getDecl());
+  }
+
+  return false;
+}
+}
+
+//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//
+
+namespace {
+/// \brief Given a type tag expression find the type tag itself.
+///
+/// \param TypeExpr Type tag expression, as it appears in user's code.
+///
+/// \param VD Declaration of an identifier that appears in a type tag.
+///
+/// \param MagicValue Type tag magic value.
+bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
+                     const ValueDecl **VD, uint64_t *MagicValue) {
+  while(true) {
+    if (!TypeExpr)
+      return false;
+
+    TypeExpr = TypeExpr->IgnoreParenImpCasts()->IgnoreParenCasts();
+
+    switch (TypeExpr->getStmtClass()) {
+    case Stmt::UnaryOperatorClass: {
+      const UnaryOperator *UO = cast<UnaryOperator>(TypeExpr);
+      if (UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_Deref) {
+        TypeExpr = UO->getSubExpr();
+        continue;
+      }
+      return false;
+    }
+
+    case Stmt::DeclRefExprClass: {
+      const DeclRefExpr *DRE = cast<DeclRefExpr>(TypeExpr);
+      *VD = DRE->getDecl();
+      return true;
+    }
+
+    case Stmt::IntegerLiteralClass: {
+      const IntegerLiteral *IL = cast<IntegerLiteral>(TypeExpr);
+      llvm::APInt MagicValueAPInt = IL->getValue();
+      if (MagicValueAPInt.getActiveBits() <= 64) {
+        *MagicValue = MagicValueAPInt.getZExtValue();
+        return true;
+      } else
+        return false;
+    }
+
+    case Stmt::BinaryConditionalOperatorClass:
+    case Stmt::ConditionalOperatorClass: {
+      const AbstractConditionalOperator *ACO =
+          cast<AbstractConditionalOperator>(TypeExpr);
+      bool Result;
+      if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx)) {
+        if (Result)
+          TypeExpr = ACO->getTrueExpr();
+        else
+          TypeExpr = ACO->getFalseExpr();
+        continue;
+      }
+      return false;
+    }
+
+    case Stmt::BinaryOperatorClass: {
+      const BinaryOperator *BO = cast<BinaryOperator>(TypeExpr);
+      if (BO->getOpcode() == BO_Comma) {
+        TypeExpr = BO->getRHS();
+        continue;
+      }
+      return false;
+    }
+
+    default:
+      return false;
+    }
+  }
+}
+
+/// \brief Retrieve the C type corresponding to type tag TypeExpr.
+///
+/// \param TypeExpr Expression that specifies a type tag.
+///
+/// \param MagicValues Registered magic values.
+///
+/// \param FoundWrongKind Set to true if a type tag was found, but of a wrong
+///        kind.
+///
+/// \param TypeInfo Information about the corresponding C type.
+///
+/// \returns true if the corresponding C type was found.
+bool GetMatchingCType(
+        const IdentifierInfo *ArgumentKind,
+        const Expr *TypeExpr, const ASTContext &Ctx,
+        const llvm::DenseMap<Sema::TypeTagMagicValue,
+                             Sema::TypeTagData> *MagicValues,
+        bool &FoundWrongKind,
+        Sema::TypeTagData &TypeInfo) {
+  FoundWrongKind = false;
+
+  // Variable declaration that has type_tag_for_datatype attribute.
+  const ValueDecl *VD = NULL;
+
+  uint64_t MagicValue;
+
+  if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue))
+    return false;
+
+  if (VD) {
+    for (specific_attr_iterator<TypeTagForDatatypeAttr>
+             I = VD->specific_attr_begin<TypeTagForDatatypeAttr>(),
+             E = VD->specific_attr_end<TypeTagForDatatypeAttr>();
+         I != E; ++I) {
+      if (I->getArgumentKind() != ArgumentKind) {
+        FoundWrongKind = true;
+        return false;
+      }
+      TypeInfo.Type = I->getMatchingCType();
+      TypeInfo.LayoutCompatible = I->getLayoutCompatible();
+      TypeInfo.MustBeNull = I->getMustBeNull();
+      return true;
+    }
+    return false;
+  }
+
+  if (!MagicValues)
+    return false;
+
+  llvm::DenseMap<Sema::TypeTagMagicValue,
+                 Sema::TypeTagData>::const_iterator I =
+      MagicValues->find(std::make_pair(ArgumentKind, MagicValue));
+  if (I == MagicValues->end())
+    return false;
+
+  TypeInfo = I->second;
+  return true;
+}
+} // unnamed namespace
+
+void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
+                                      uint64_t MagicValue, QualType Type,
+                                      bool LayoutCompatible,
+                                      bool MustBeNull) {
+  if (!TypeTagForDatatypeMagicValues)
+    TypeTagForDatatypeMagicValues.reset(
+        new llvm::DenseMap<TypeTagMagicValue, TypeTagData>);
+
+  TypeTagMagicValue Magic(ArgumentKind, MagicValue);
+  (*TypeTagForDatatypeMagicValues)[Magic] =
+      TypeTagData(Type, LayoutCompatible, MustBeNull);
+}
+
+namespace {
+bool IsSameCharType(QualType T1, QualType T2) {
+  const BuiltinType *BT1 = T1->getAs<BuiltinType>();
+  if (!BT1)
+    return false;
+
+  const BuiltinType *BT2 = T2->getAs<BuiltinType>();
+  if (!BT2)
+    return false;
+
+  BuiltinType::Kind T1Kind = BT1->getKind();
+  BuiltinType::Kind T2Kind = BT2->getKind();
+
+  return (T1Kind == BuiltinType::SChar  && T2Kind == BuiltinType::Char_S) ||
+         (T1Kind == BuiltinType::UChar  && T2Kind == BuiltinType::Char_U) ||
+         (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) ||
+         (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar);
+}
+} // unnamed namespace
+
+void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
+                                    const Expr * const *ExprArgs) {
+  const IdentifierInfo *ArgumentKind = Attr->getArgumentKind();
+  bool IsPointerAttr = Attr->getIsPointer();
+
+  const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()];
+  bool FoundWrongKind;
+  TypeTagData TypeInfo;
+  if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context,
+                        TypeTagForDatatypeMagicValues.get(),
+                        FoundWrongKind, TypeInfo)) {
+    if (FoundWrongKind)
+      Diag(TypeTagExpr->getExprLoc(),
+           diag::warn_type_tag_for_datatype_wrong_kind)
+        << TypeTagExpr->getSourceRange();
+    return;
+  }
+
+  const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()];
+  if (IsPointerAttr) {
+    // Skip implicit cast of pointer to `void *' (as a function argument).
+    if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr))
+      if (ICE->getType()->isVoidPointerType())
+        ArgumentExpr = ICE->getSubExpr();
+  }
+  QualType ArgumentType = ArgumentExpr->getType();
+
+  // Passing a `void*' pointer shouldn't trigger a warning.
+  if (IsPointerAttr && ArgumentType->isVoidPointerType())
+    return;
+
+  if (TypeInfo.MustBeNull) {
+    // Type tag with matching void type requires a null pointer.
+    if (!ArgumentExpr->isNullPointerConstant(Context,
+                                             Expr::NPC_ValueDependentIsNotNull)) {
+      Diag(ArgumentExpr->getExprLoc(),
+           diag::warn_type_safety_null_pointer_required)
+          << ArgumentKind->getName()
+          << ArgumentExpr->getSourceRange()
+          << TypeTagExpr->getSourceRange();
+    }
+    return;
+  }
+
+  QualType RequiredType = TypeInfo.Type;
+  if (IsPointerAttr)
+    RequiredType = Context.getPointerType(RequiredType);
+
+  bool mismatch = false;
+  if (!TypeInfo.LayoutCompatible) {
+    mismatch = !Context.hasSameType(ArgumentType, RequiredType);
+
+    // C++11 [basic.fundamental] p1:
+    // Plain char, signed char, and unsigned char are three distinct types.
+    //
+    // But we treat plain `char' as equivalent to `signed char' or `unsigned
+    // char' depending on the current char signedness mode.
+    if (mismatch)
+      if ((IsPointerAttr && IsSameCharType(ArgumentType->getPointeeType(),
+                                           RequiredType->getPointeeType())) ||
+          (!IsPointerAttr && IsSameCharType(ArgumentType, RequiredType)))
+        mismatch = false;
+  } else
+    if (IsPointerAttr)
+      mismatch = !isLayoutCompatible(Context,
+                                     ArgumentType->getPointeeType(),
+                                     RequiredType->getPointeeType());
+    else
+      mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType);
+
+  if (mismatch)
+    Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch)
+        << ArgumentType << ArgumentKind->getName()
+        << TypeInfo.LayoutCompatible << RequiredType
+        << ArgumentExpr->getSourceRange()
+        << TypeTagExpr->getSourceRange();
+}
+

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug 16 19:08:38 2012
@@ -7031,6 +7031,42 @@
 Sema::FinalizeDeclaration(Decl *ThisDecl) {
   // Note that we are no longer parsing the initializer for this declaration.
   ParsingInitForAutoVars.erase(ThisDecl);
+
+  // Now we have parsed the initializer and can update the table of magic
+  // tag values.
+  if (ThisDecl && ThisDecl->hasAttr<TypeTagForDatatypeAttr>()) {
+    const VarDecl *VD = dyn_cast<VarDecl>(ThisDecl);
+    if (VD && VD->getType()->isIntegralOrEnumerationType()) {
+      for (specific_attr_iterator<TypeTagForDatatypeAttr>
+               I = ThisDecl->specific_attr_begin<TypeTagForDatatypeAttr>(),
+               E = ThisDecl->specific_attr_end<TypeTagForDatatypeAttr>();
+           I != E; ++I) {
+        const Expr *MagicValueExpr = VD->getInit();
+        if (!MagicValueExpr) {
+          continue;
+        }
+        llvm::APSInt MagicValueInt;
+        if (!MagicValueExpr->isIntegerConstantExpr(MagicValueInt, Context)) {
+          Diag(I->getRange().getBegin(),
+               diag::err_type_tag_for_datatype_not_ice)
+            << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
+          continue;
+        }
+        if (MagicValueInt.getActiveBits() > 64) {
+          Diag(I->getRange().getBegin(),
+               diag::err_type_tag_for_datatype_too_large)
+            << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
+          continue;
+        }
+        uint64_t MagicValue = MagicValueInt.getZExtValue();
+        RegisterTypeTagForDatatype(I->getArgumentKind(),
+                                   MagicValue,
+                                   I->getMatchingCType(),
+                                   I->getLayoutCompatible(),
+                                   I->getMustBeNull());
+      }
+    }
+  }
 }
 
 Sema::DeclGroupPtrTy

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Aug 16 19:08:38 2012
@@ -221,6 +221,53 @@
   return true;
 }
 
+/// \brief Check if IdxExpr is a valid argument index for a function or
+/// instance method D.  May output an error.
+///
+/// \returns true if IdxExpr is a valid index.
+static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D,
+                                               StringRef AttrName,
+                                               SourceLocation AttrLoc,
+                                               unsigned AttrArgNum,
+                                               const Expr *IdxExpr,
+                                               uint64_t &Idx)
+{
+  assert(isFunctionOrMethod(D) && hasFunctionProto(D));
+
+  // In C++ the implicit 'this' function parameter also counts.
+  // Parameters are counted from one.
+  const bool HasImplicitThisParam = isInstanceMethod(D);
+  const unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+  const unsigned FirstIdx = 1;
+
+  llvm::APSInt IdxInt;
+  if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
+      !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) {
+    S.Diag(AttrLoc, diag::err_attribute_argument_n_not_int)
+      << AttrName << AttrArgNum << IdxExpr->getSourceRange();
+    return false;
+  }
+
+  Idx = IdxInt.getLimitedValue();
+  if (Idx < FirstIdx || (!isFunctionOrMethodVariadic(D) && Idx > NumArgs)) {
+    S.Diag(AttrLoc, diag::err_attribute_argument_out_of_bounds)
+      << AttrName << AttrArgNum << IdxExpr->getSourceRange();
+    return false;
+  }
+  Idx--; // Convert to zero-based.
+  if (HasImplicitThisParam) {
+    if (Idx == 0) {
+      S.Diag(AttrLoc,
+             diag::err_attribute_invalid_implicit_this_argument)
+        << AttrName << IdxExpr->getSourceRange();
+      return false;
+    }
+    --Idx;
+  }
+
+  return true;
+}
+
 ///
 /// \brief Check if passed in Decl is a field or potentially shared global var
 /// \return true if the Decl is a field or potentially shared global variable
@@ -3696,6 +3743,79 @@
   }
 }
 
+static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
+                                          const AttributeList &Attr) {
+  StringRef AttrName = Attr.getName()->getName();
+  if (!Attr.getParameterName()) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_identifier)
+      << Attr.getName() << /* arg num = */ 1;
+    return;
+  }
+
+  if (Attr.getNumArgs() != 2) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+      << /* required args = */ 3;
+    return;
+  }
+
+  IdentifierInfo *ArgumentKind = Attr.getParameterName();
+
+  if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  uint64_t ArgumentIdx;
+  if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName,
+                                          Attr.getLoc(), 2,
+                                          Attr.getArg(0), ArgumentIdx))
+    return;
+
+  uint64_t TypeTagIdx;
+  if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName,
+                                          Attr.getLoc(), 3,
+                                          Attr.getArg(1), TypeTagIdx))
+    return;
+
+  bool IsPointer = (AttrName == "pointer_with_type_tag");
+  if (IsPointer) {
+    // Ensure that buffer has a pointer type.
+    QualType BufferTy = getFunctionOrMethodArgType(D, ArgumentIdx);
+    if (!BufferTy->isPointerType()) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only)
+        << AttrName;
+    }
+  }
+
+  D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(Attr.getRange(),
+                                                       S.Context,
+                                                       ArgumentKind,
+                                                       ArgumentIdx,
+                                                       TypeTagIdx,
+                                                       IsPointer));
+}
+
+static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
+                                         const AttributeList &Attr) {
+  IdentifierInfo *PointerKind = Attr.getParameterName();
+  if (!PointerKind) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_identifier)
+      << "type_tag_for_datatype" << 1;
+    return;
+  }
+
+  QualType MatchingCType = S.GetTypeFromParser(Attr.getMatchingCType(), NULL);
+
+  D->addAttr(::new (S.Context) TypeTagForDatatypeAttr(
+                                  Attr.getRange(),
+                                  S.Context,
+                                  PointerKind,
+                                  MatchingCType,
+                                  Attr.getLayoutCompatible(),
+                                  Attr.getMustBeNull()));
+}
+
 //===----------------------------------------------------------------------===//
 // Checker-specific attribute handlers.
 //===----------------------------------------------------------------------===//
@@ -4326,6 +4446,14 @@
     handleAcquiredAfterAttr(S, D, Attr);
     break;
 
+  // Type safety attributes.
+  case AttributeList::AT_ArgumentWithTypeTag:
+    handleArgumentWithTypeTagAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_TypeTagForDatatype:
+    handleTypeTagForDatatypeAttr(S, D, Attr);
+    break;
+
   default:
     // Ask target about the attribute.
     const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();

Modified: cfe/trunk/test/Sema/128bitint.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/128bitint.c?rev=162067&r1=162066&r2=162067&view=diff
==============================================================================
--- cfe/trunk/test/Sema/128bitint.c (original)
+++ cfe/trunk/test/Sema/128bitint.c Thu Aug 16 19:08:38 2012
@@ -18,3 +18,22 @@
 unsigned long long UnsignedTooBig = 123456789012345678901234567890; // expected-warning {{integer constant is too large for its type}}
 __uint128_t Unsigned128 = 123456789012345678901234567890Ui128;
 unsigned long long Unsigned64 = 123456789012345678901234567890Ui128; // expected-warning {{implicit conversion from 'unsigned __int128' to 'unsigned long long' changes value from 123456789012345678901234567890 to 14083847773837265618}}
+
+// Ensure we don't crash when user passes 128-bit values to type safety
+// attributes.
+void pointer_with_type_tag_arg_num_1(void *buf, int datatype)
+    __attribute__(( pointer_with_type_tag(mpi,0x10000000000000001i128,1) )); // expected-error {{attribute parameter 2 is out of bounds}}
+
+void pointer_with_type_tag_arg_num_2(void *buf, int datatype)
+    __attribute__(( pointer_with_type_tag(mpi,1,0x10000000000000001i128) )); // expected-error {{attribute parameter 3 is out of bounds}}
+
+void MPI_Send(void *buf, int datatype) __attribute__(( pointer_with_type_tag(mpi,1,2) ));
+
+static const __uint128_t mpi_int_wrong __attribute__(( type_tag_for_datatype(mpi,int) )) = 0x10000000000000001i128; // expected-error {{'type_tag_for_datatype' attribute requires the initializer to be an integer constant expression that can be represented by a 64 bit integer}}
+static const int mpi_int __attribute__(( type_tag_for_datatype(mpi,int) )) = 10;
+
+void test(int *buf)
+{
+  MPI_Send(buf, 0x10000000000000001i128); // expected-warning {{implicit conversion from '__int128' to 'int' changes value}}
+}
+

Added: cfe/trunk/test/Sema/warn-type-safety-mpi-hdf5.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-type-safety-mpi-hdf5.c?rev=162067&view=auto
==============================================================================
--- cfe/trunk/test/Sema/warn-type-safety-mpi-hdf5.c (added)
+++ cfe/trunk/test/Sema/warn-type-safety-mpi-hdf5.c Thu Aug 16 19:08:38 2012
@@ -0,0 +1,307 @@
+// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c99 -DMPICH -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -DOPEN_MPI -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -DMPICH -fsyntax-only -verify %s
+//
+// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fno-signed-char -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c99 -DMPICH -fno-signed-char -fsyntax-only -verify %s
+
+//===--- limits.h mock ----------------------------------------------------===//
+
+#ifdef __CHAR_UNSIGNED__
+#define CHAR_MIN 0
+#define CHAR_MAX (__SCHAR_MAX__*2  +1)
+#else
+#define CHAR_MIN (-__SCHAR_MAX__-1)
+#define CHAR_MAX __SCHAR_MAX__
+#endif
+
+//===--- mpi.h mock -------------------------------------------------------===//
+
+#define NULL ((void *)0)
+
+#ifdef OPEN_MPI
+typedef struct ompi_datatype_t *MPI_Datatype;
+#endif
+
+#ifdef MPICH
+typedef int MPI_Datatype;
+#endif
+
+int MPI_Send(void *buf, int count, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag(mpi,1,3) ));
+
+int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
+               void *recvbuf, int recvcount, MPI_Datatype recvtype)
+               __attribute__(( pointer_with_type_tag(mpi,1,3), pointer_with_type_tag(mpi,4,6) ));
+
+#ifdef OPEN_MPI
+// OpenMPI and LAM/MPI-style datatype definitions
+
+#define OMPI_PREDEFINED_GLOBAL(type, global) ((type) &(global))
+
+#define MPI_DATATYPE_NULL OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_datatype_null)
+#define MPI_FLOAT         OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_float)
+#define MPI_INT           OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_int)
+#define MPI_LONG          OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_long)
+#define MPI_LONG_LONG_INT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_long_long_int)
+#define MPI_CHAR          OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_char)
+
+#define MPI_FLOAT_INT     OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_float_int)
+#define MPI_2INT          OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_2int)
+
+#define MPI_IN_PLACE ((void *) 1)
+
+extern struct ompi_predefined_datatype_t ompi_mpi_datatype_null __attribute__(( type_tag_for_datatype(mpi,void,must_be_null) ));
+extern struct ompi_predefined_datatype_t ompi_mpi_float         __attribute__(( type_tag_for_datatype(mpi,float) ));
+extern struct ompi_predefined_datatype_t ompi_mpi_int           __attribute__(( type_tag_for_datatype(mpi,int) ));
+extern struct ompi_predefined_datatype_t ompi_mpi_long          __attribute__(( type_tag_for_datatype(mpi,long) ));
+extern struct ompi_predefined_datatype_t ompi_mpi_long_long_int __attribute__(( type_tag_for_datatype(mpi,long long int) ));
+extern struct ompi_predefined_datatype_t ompi_mpi_char          __attribute__(( type_tag_for_datatype(mpi,char) ));
+
+struct ompi_struct_mpi_float_int {float f; int i;};
+extern struct ompi_predefined_datatype_t ompi_mpi_float_int     __attribute__(( type_tag_for_datatype(mpi, struct ompi_struct_mpi_float_int, layout_compatible) ));
+
+struct ompi_struct_mpi_2int {int i1; int i2;};
+extern struct ompi_predefined_datatype_t ompi_mpi_2int          __attribute__(( type_tag_for_datatype(mpi, struct ompi_struct_mpi_2int, layout_compatible) ));
+#endif
+
+#ifdef MPICH
+// MPICH2 and MVAPICH2-style datatype definitions
+
+#define MPI_COMM_WORLD ((MPI_Comm) 0x44000000)
+
+#define MPI_DATATYPE_NULL ((MPI_Datatype) 0xa0000000)
+#define MPI_FLOAT         ((MPI_Datatype) 0xa0000001)
+#define MPI_INT           ((MPI_Datatype) 0xa0000002)
+#define MPI_LONG          ((MPI_Datatype) 0xa0000003)
+#define MPI_LONG_LONG_INT ((MPI_Datatype) 0xa0000004)
+#define MPI_CHAR          ((MPI_Datatype) 0xa0000005)
+
+#define MPI_FLOAT_INT     ((MPI_Datatype) 0xa0000006)
+#define MPI_2INT          ((MPI_Datatype) 0xa0000007)
+
+#define MPI_IN_PLACE  (void *) -1
+
+static const MPI_Datatype mpich_mpi_datatype_null __attribute__(( type_tag_for_datatype(mpi,void,must_be_null) )) = 0xa0000000;
+static const MPI_Datatype mpich_mpi_float         __attribute__(( type_tag_for_datatype(mpi,float) ))             = 0xa0000001;
+static const MPI_Datatype mpich_mpi_int           __attribute__(( type_tag_for_datatype(mpi,int) ))               = 0xa0000002;
+static const MPI_Datatype mpich_mpi_long          __attribute__(( type_tag_for_datatype(mpi,long) ))              = 0xa0000003;
+static const MPI_Datatype mpich_mpi_long_long_int __attribute__(( type_tag_for_datatype(mpi,long long int) ))     = 0xa0000004;
+static const MPI_Datatype mpich_mpi_char          __attribute__(( type_tag_for_datatype(mpi,char) ))              = 0xa0000005;
+
+struct mpich_struct_mpi_float_int { float f; int i; };
+struct mpich_struct_mpi_2int { int i1; int i2; };
+static const MPI_Datatype mpich_mpi_float_int     __attribute__(( type_tag_for_datatype(mpi, struct mpich_struct_mpi_float_int, layout_compatible) )) = 0xa0000006;
+static const MPI_Datatype mpich_mpi_2int          __attribute__(( type_tag_for_datatype(mpi, struct mpich_struct_mpi_2int, layout_compatible) )) = 0xa0000007;
+#endif
+
+//===--- HDF5 headers mock ------------------------------------------------===//
+
+typedef int hid_t;
+void H5open(void);
+
+#ifndef HDF_PRIVATE
+#define H5OPEN  H5open(),
+#else
+#define H5OPEN
+#endif
+
+#define H5T_NATIVE_CHAR         (CHAR_MIN?H5T_NATIVE_SCHAR:H5T_NATIVE_UCHAR)
+#define H5T_NATIVE_SCHAR        (H5OPEN H5T_NATIVE_SCHAR_g)
+#define H5T_NATIVE_UCHAR        (H5OPEN H5T_NATIVE_UCHAR_g)
+#define H5T_NATIVE_INT          (H5OPEN H5T_NATIVE_INT_g)
+#define H5T_NATIVE_LONG         (H5OPEN H5T_NATIVE_LONG_g)
+
+hid_t H5T_NATIVE_SCHAR_g __attribute__(( type_tag_for_datatype(hdf5,signed char) ));
+hid_t H5T_NATIVE_UCHAR_g __attribute__(( type_tag_for_datatype(hdf5,unsigned char) ));
+hid_t H5T_NATIVE_INT_g   __attribute__(( type_tag_for_datatype(hdf5,int) ));
+hid_t H5T_NATIVE_LONG_g  __attribute__(( type_tag_for_datatype(hdf5,long) ));
+
+void H5Dwrite(hid_t mem_type_id, const void *buf) __attribute__(( pointer_with_type_tag(hdf5,2,1) ));
+
+//===--- Tests ------------------------------------------------------------===//
+
+//===--- MPI
+
+struct pair_float_int
+{
+  float f; int i;
+};
+
+struct pair_int_int
+{
+  int i1; int i2;
+};
+
+void test_mpi_predefined_types(
+    int *int_buf,
+    long *long_buf1,
+    long *long_buf2,
+    void *void_buf,
+    struct pair_float_int *pfi,
+    struct pair_int_int *pii)
+{
+  char char_buf[255];
+
+  // Layout-compatible scalar types.
+  MPI_Send(int_buf,   1, MPI_INT); // no-warning
+
+  // Layout-compatible class types.
+  MPI_Send(pfi, 1, MPI_FLOAT_INT); // no-warning
+  MPI_Send(pii, 1, MPI_2INT); // no-warning
+
+  // Layout-incompatible scalar types.
+  MPI_Send(long_buf1, 1, MPI_INT); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}}
+
+  // Layout-incompatible class types.
+  MPI_Send(pii, 1, MPI_FLOAT_INT); // expected-warning {{argument type 'struct pair_int_int *' doesn't match specified 'mpi' type tag}}
+  MPI_Send(pfi, 1, MPI_2INT); // expected-warning {{argument type 'struct pair_float_int *' doesn't match specified 'mpi' type tag}}
+
+  // Layout-incompatible class-scalar types.
+  MPI_Send(long_buf1, 1, MPI_2INT); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag}}
+
+  // Function with two buffers.
+  MPI_Gather(long_buf1, 1, MPI_INT,  // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}}
+             long_buf2, 1, MPI_INT); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}}
+
+  // Array buffers should work like pointer buffers.
+  MPI_Send(char_buf,  255, MPI_CHAR); // no-warning
+
+  // Explicit casts should not be dropped.
+  MPI_Send((int *) char_buf,  255, MPI_INT); // no-warning
+  MPI_Send((int *) char_buf,  255, MPI_CHAR); // expected-warning {{argument type 'int *' doesn't match specified 'mpi' type tag that requires 'char *'}}
+
+  // `void*' buffer should never warn.
+  MPI_Send(void_buf,  255, MPI_CHAR); // no-warning
+
+  // We expect that MPI_IN_PLACE is `void*', shouldn't warn.
+  MPI_Gather(MPI_IN_PLACE, 0, MPI_INT,
+             int_buf,      1, MPI_INT);
+
+  // Special handling for MPI_DATATYPE_NULL: buffer pointer should be either
+  // a `void*' pointer or a null pointer constant.
+  MPI_Gather(NULL,    0, MPI_DATATYPE_NULL, // no-warning
+             int_buf, 1, MPI_INT);
+
+  MPI_Gather(int_buf, 0, MPI_DATATYPE_NULL, // expected-warning {{specified mpi type tag requires a null pointer}}
+             int_buf, 1, MPI_INT);
+}
+
+MPI_Datatype my_int_datatype __attribute__(( type_tag_for_datatype(mpi,int) ));
+
+struct S1 { int a; int b; };
+MPI_Datatype my_s1_datatype __attribute__(( type_tag_for_datatype(mpi,struct S1) ));
+
+// Layout-compatible to S1, but should be treated as a different type.
+struct S2 { int a; int b; };
+MPI_Datatype my_s2_datatype __attribute__(( type_tag_for_datatype(mpi,struct S2) ));
+
+void test_user_types(int *int_buf,
+                     long *long_buf,
+                     struct S1 *s1_buf,
+                     struct S2 *s2_buf)
+{
+  MPI_Send(int_buf,  1, my_int_datatype); // no-warning
+  MPI_Send(long_buf, 1, my_int_datatype); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}}
+
+  MPI_Send(s1_buf, 1, my_s1_datatype); // no-warning
+  MPI_Send(s1_buf, 1, my_s2_datatype); // expected-warning {{argument type 'struct S1 *' doesn't match specified 'mpi' type tag that requires 'struct S2 *'}}
+
+  MPI_Send(long_buf, 1, my_s1_datatype); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'struct S1 *'}}
+  MPI_Send(s1_buf, 1, MPI_INT); // expected-warning {{argument type 'struct S1 *' doesn't match specified 'mpi' type tag that requires 'int *'}}
+}
+
+MPI_Datatype my_unknown_datatype;
+
+void test_not_annotated(int *int_buf,
+                        long *long_buf,
+                        MPI_Datatype type)
+{
+  // Using 'MPI_Datatype's without attributes should not produce warnings.
+  MPI_Send(long_buf, 1, my_unknown_datatype); // no-warning
+  MPI_Send(int_buf, 1, type); // no-warning
+}
+
+struct S1_compat { int a; int b; };
+MPI_Datatype my_s1_compat_datatype
+    __attribute__(( type_tag_for_datatype(mpi, struct S1_compat, layout_compatible) ));
+
+struct S3        { int a; long b; double c; double d; struct S1 s1; };
+struct S3_compat { int a; long b; double c; double d; struct S2 s2; };
+MPI_Datatype my_s3_compat_datatype
+    __attribute__(( type_tag_for_datatype(mpi, struct S3_compat, layout_compatible) ));
+
+struct S4        { char c; };
+struct S4_compat { signed char c; };
+MPI_Datatype my_s4_compat_datatype
+    __attribute__(( type_tag_for_datatype(mpi, struct S4_compat, layout_compatible) ));
+
+union U1        { int a; long b; double c; double d; struct S1 s1; };
+union U1_compat { long b; double c; struct S2 s; int a; double d; };
+MPI_Datatype my_u1_compat_datatype
+    __attribute__(( type_tag_for_datatype(mpi, union U1_compat, layout_compatible) ));
+
+union U2 { int a; long b; double c; struct S1 s1; };
+MPI_Datatype my_u2_datatype
+    __attribute__(( type_tag_for_datatype(mpi, union U2, layout_compatible) ));
+
+void test_layout_compatibility(struct S1 *s1_buf, struct S3 *s3_buf,
+                               struct S4 *s4_buf,
+                               union U1 *u1_buf, union U2 *u2_buf)
+{
+  MPI_Send(s1_buf, 1, my_s1_compat_datatype); // no-warning
+  MPI_Send(s3_buf, 1, my_s3_compat_datatype); // no-warning
+  MPI_Send(s1_buf, 1, my_s3_compat_datatype); // expected-warning {{argument type 'struct S1 *' doesn't match specified 'mpi' type tag}}
+  MPI_Send(s4_buf, 1, my_s4_compat_datatype); // expected-warning {{argument type 'struct S4 *' doesn't match specified 'mpi' type tag}}
+  MPI_Send(u1_buf, 1, my_u1_compat_datatype); // no-warning
+  MPI_Send(u1_buf, 1, my_u2_datatype);        // expected-warning {{argument type 'union U1 *' doesn't match specified 'mpi' type tag}}
+  MPI_Send(u2_buf, 1, my_u1_compat_datatype); // expected-warning {{argument type 'union U2 *' doesn't match specified 'mpi' type tag}}
+}
+
+// There is an MPI_REAL predefined in MPI, but some existing MPI programs do
+// this.
+typedef float real;
+#define MPI_REAL MPI_FLOAT
+
+void test_mpi_real_user_type(real *real_buf, float *float_buf)
+{
+  MPI_Send(real_buf,  1, MPI_REAL);  // no-warning
+  MPI_Send(real_buf,  1, MPI_FLOAT); // no-warning
+  MPI_Send(float_buf, 1, MPI_REAL);  // no-warning
+  MPI_Send(float_buf, 1, MPI_FLOAT); // no-warning
+}
+
+//===--- HDF5
+
+void test_hdf5(char *char_buf,
+               signed char *schar_buf,
+               unsigned char *uchar_buf,
+               int *int_buf,
+               long *long_buf)
+{
+  H5Dwrite(H5T_NATIVE_CHAR,  char_buf);  // no-warning
+#ifdef __CHAR_UNSIGNED__
+  H5Dwrite(H5T_NATIVE_CHAR,  schar_buf); // expected-warning {{argument type 'signed char *' doesn't match specified 'hdf5' type tag that requires 'unsigned char *'}}
+  H5Dwrite(H5T_NATIVE_CHAR,  uchar_buf); // no-warning
+#else
+  H5Dwrite(H5T_NATIVE_CHAR,  schar_buf); // no-warning
+  H5Dwrite(H5T_NATIVE_CHAR,  uchar_buf); // expected-warning {{argument type 'unsigned char *' doesn't match specified 'hdf5' type tag that requires 'signed char *'}}
+#endif
+  H5Dwrite(H5T_NATIVE_SCHAR, schar_buf); // no-warning
+  H5Dwrite(H5T_NATIVE_UCHAR, uchar_buf); // no-warning
+  H5Dwrite(H5T_NATIVE_INT,   int_buf);   // no-warning
+  H5Dwrite(H5T_NATIVE_LONG,  long_buf);  // no-warning
+
+#ifdef __CHAR_UNSIGNED__
+  H5Dwrite(H5T_NATIVE_CHAR,  int_buf);  // expected-warning {{argument type 'int *' doesn't match specified 'hdf5' type tag that requires 'unsigned char *'}}
+#else
+  H5Dwrite(H5T_NATIVE_CHAR,  int_buf);  // expected-warning {{argument type 'int *' doesn't match specified 'hdf5' type tag that requires 'signed char *'}}
+#endif
+  H5Dwrite(H5T_NATIVE_INT,   long_buf); // expected-warning {{argument type 'long *' doesn't match specified 'hdf5' type tag that requires 'int *'}}
+
+  // FIXME: we should warn here, but it will cause false positives because
+  // different kinds may use same magic values.
+  //H5Dwrite(MPI_INT, int_buf);
+}
+

Added: cfe/trunk/test/Sema/warn-type-safety.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-type-safety.c?rev=162067&view=auto
==============================================================================
--- cfe/trunk/test/Sema/warn-type-safety.c (added)
+++ cfe/trunk/test/Sema/warn-type-safety.c Thu Aug 16 19:08:38 2012
@@ -0,0 +1,152 @@
+// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c99 -fno-signed-char -fsyntax-only -verify %s
+
+struct A {};
+
+typedef struct A *MPI_Datatype;
+
+int wrong1(void *buf, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag )); // expected-error {{attribute requires parameter 1 to be an identifier}}
+
+int wrong2(void *buf, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag(mpi,0,7) )); // expected-error {{attribute parameter 2 is out of bounds}}
+
+int wrong3(void *buf, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag(mpi,3,7) )); // expected-error {{attribute parameter 2 is out of bounds}}
+
+int wrong4(void *buf, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag(mpi,1,0) )); // expected-error {{attribute parameter 3 is out of bounds}}
+
+int wrong5(void *buf, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag(mpi,1,3) )); // expected-error {{attribute parameter 3 is out of bounds}}
+
+int wrong6(void *buf, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag(mpi,0x8000000000000001ULL,1) )); // expected-error {{attribute parameter 2 is out of bounds}}
+
+extern int x;
+
+int wrong7(void *buf, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag(mpi,x,2) )); // expected-error {{attribute requires parameter 2 to be an integer constant}}
+
+int wrong8(void *buf, MPI_Datatype datatype)
+    __attribute__(( pointer_with_type_tag(mpi,1,x) )); // expected-error {{attribute requires parameter 3 to be an integer constant}}
+
+int wrong9 __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{attribute only applies to functions and methods}}
+
+int wrong10(double buf, MPI_Datatype type)
+    __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{'pointer_with_type_tag' attribute only applies to pointer arguments}}
+
+
+extern struct A datatype_wrong1
+    __attribute__(( type_tag_for_datatype )); // expected-error {{attribute requires parameter 1 to be an identifier}}
+
+extern struct A datatype_wrong2
+    __attribute__(( type_tag_for_datatype(mpi,1,2) )); // expected-error {{expected a type}}
+
+extern struct A datatype_wrong3
+    __attribute__(( type_tag_for_datatype(mpi,not_a_type) )); // expected-error {{unknown type name 'not_a_type'}}
+
+extern struct A datatype_wrong4
+    __attribute__(( type_tag_for_datatype(mpi,int,int) )); // expected-error {{expected identifier}}
+
+extern struct A datatype_wrong5
+    __attribute__(( type_tag_for_datatype(mpi,int,not_a_flag) )); // expected-error {{invalid comparison flag 'not_a_flag'}}
+
+extern struct A datatype_wrong6
+    __attribute__(( type_tag_for_datatype(mpi,int,layout_compatible,not_a_flag) )); // expected-error {{invalid comparison flag 'not_a_flag'}}
+
+
+// Using a tag with kind A in a place where the function requires kind B should
+// warn.
+
+void A_func(void *ptr, void *tag) __attribute__(( pointer_with_type_tag(a,1,2) ));
+
+extern struct A A_tag __attribute__(( type_tag_for_datatype(a,int) ));
+extern struct A B_tag __attribute__(( type_tag_for_datatype(b,int) ));
+
+void C_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(c,1,2) ));
+
+static const int C_tag __attribute__(( type_tag_for_datatype(c,int) )) = 10;
+static const int D_tag __attribute__(( type_tag_for_datatype(d,int) )) = 20;
+
+void test_tag_mismatch(int *ptr)
+{
+  A_func(ptr, &A_tag); // no-warning
+  A_func(ptr, &B_tag); // expected-warning {{this type tag was not designed to be used with this function}}
+  C_func(ptr, C_tag); // no-warning
+  C_func(ptr, D_tag); // expected-warning {{this type tag was not designed to be used with this function}}
+  C_func(ptr, 10); // no-warning
+  C_func(ptr, 20); // should warn, but may cause false positives
+}
+
+// Check that we look through typedefs in the special case of allowing 'char'
+// to be matched with 'signed char' or 'unsigned char'.
+void E_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(e,1,2) ));
+
+typedef char E_char;
+typedef char E_char_2;
+typedef signed char E_char_signed;
+typedef unsigned char E_char_unsigned;
+
+static const int E_tag __attribute__(( type_tag_for_datatype(e,E_char) )) = 10;
+
+void test_char_typedef(char *char_buf,
+                       E_char_2 *e_char_buf,
+                       E_char_signed *e_char_signed_buf,
+                       E_char_unsigned *e_char_unsigned_buf)
+{
+  E_func(char_buf, E_tag);
+  E_func(e_char_buf, E_tag);
+#ifdef __CHAR_UNSIGNED__
+  E_func(e_char_signed_buf, E_tag); // expected-warning {{argument type 'E_char_signed *' (aka 'signed char *') doesn't match specified 'e' type tag that requires 'E_char *' (aka 'char *')}}
+  E_func(e_char_unsigned_buf, E_tag);
+#else
+  E_func(e_char_signed_buf, E_tag);
+  E_func(e_char_unsigned_buf, E_tag); // expected-warning {{argument type 'E_char_unsigned *' (aka 'unsigned char *') doesn't match specified 'e' type tag that requires 'E_char *' (aka 'char *')}}
+#endif
+}
+
+// Tests for argument_with_type_tag.
+
+#define F_DUPFD 10
+#define F_SETLK 20
+
+struct flock { };
+
+static const int F_DUPFD_tag __attribute__(( type_tag_for_datatype(fcntl,int) )) = F_DUPFD;
+static const int F_SETLK_tag __attribute__(( type_tag_for_datatype(fcntl,struct flock *) )) = F_SETLK;
+
+int fcntl(int fd, int cmd, ...) __attribute__(( argument_with_type_tag(fcntl,3,2) ));
+
+void test_argument_with_type_tag(struct flock *f)
+{
+  fcntl(0, F_DUPFD, 10); // no-warning
+  fcntl(0, F_SETLK, f);  // no-warning
+
+  fcntl(0, F_SETLK, 10); // expected-warning {{argument type 'int' doesn't match specified 'fcntl' type tag that requires 'struct flock *'}}
+  fcntl(0, F_DUPFD, f);  // expected-warning {{argument type 'struct flock *' doesn't match specified 'fcntl' type tag that requires 'int'}}
+}
+
+void test_tag_expresssion(int b) {
+  fcntl(0, b ? F_DUPFD : F_SETLK, 10); // no-warning
+  fcntl(0, b + F_DUPFD, 10); // no-warning
+  fcntl(0, (b, F_DUPFD), 10); // expected-warning {{expression result unused}}
+}
+
+// Check that using 64-bit magic values as tags works and tag values do not
+// overflow internally.
+void F_func(void *ptr, unsigned long long tag) __attribute__((pointer_with_type_tag(f,1,2) ));
+
+static const unsigned long long F_tag1 __attribute__(( type_tag_for_datatype(f,int) )) = 0xFFFFFFFFFFFFFFFFULL;
+static const unsigned long long F_tag2 __attribute__(( type_tag_for_datatype(f,float) )) = 0xFFFFFFFFULL;
+
+void test_64bit_magic(int *int_ptr, float *float_ptr)
+{
+  F_func(int_ptr,   0xFFFFFFFFFFFFFFFFULL);
+  F_func(int_ptr,   0xFFFFFFFFULL);         // expected-warning {{argument type 'int *' doesn't match specified 'f' type tag that requires 'float *'}}
+  F_func(float_ptr, 0xFFFFFFFFFFFFFFFFULL); // expected-warning {{argument type 'float *' doesn't match specified 'f' type tag that requires 'int *'}}
+  F_func(float_ptr, 0xFFFFFFFFULL);
+}
+
+

Added: cfe/trunk/test/Sema/warn-type-safety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-type-safety.cpp?rev=162067&view=auto
==============================================================================
--- cfe/trunk/test/Sema/warn-type-safety.cpp (added)
+++ cfe/trunk/test/Sema/warn-type-safety.cpp Thu Aug 16 19:08:38 2012
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef struct ompi_datatype_t *MPI_Datatype;
+
+#define OMPI_PREDEFINED_GLOBAL(type, global) ((type) &(global))
+
+#define MPI_FLOAT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_float)
+#define MPI_INT   OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_int)
+#define MPI_NULL  OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_null)
+
+extern struct ompi_predefined_datatype_t ompi_mpi_float __attribute__(( type_tag_for_datatype(mpi,float) ));
+extern struct ompi_predefined_datatype_t ompi_mpi_int   __attribute__(( type_tag_for_datatype(mpi,int) ));
+extern struct ompi_predefined_datatype_t ompi_mpi_null  __attribute__(( type_tag_for_datatype(mpi,void,must_be_null) ));
+
+int f(int x) { return x; }
+static const int wrong_init __attribute__(( type_tag_for_datatype(zzz,int) )) = f(100); // expected-error {{'type_tag_for_datatype' attribute requires the initializer to be an integral constant expression}}
+
+//===--- Tests ------------------------------------------------------------===//
+// Check that hidden 'this' is handled correctly.
+
+class C
+{
+public:
+  void f1(void *buf, int count, MPI_Datatype datatype)
+       __attribute__(( pointer_with_type_tag(mpi,5,6) )); // expected-error {{attribute parameter 2 is out of bounds}}
+
+  void f2(void *buf, int count, MPI_Datatype datatype)
+       __attribute__(( pointer_with_type_tag(mpi,2,5) )); // expected-error {{attribute parameter 3 is out of bounds}}
+
+  void f3(void *buf, int count, MPI_Datatype datatype)
+       __attribute__(( pointer_with_type_tag(mpi,1,5) )); // expected-error {{attribute is invalid for the implicit this argument}}
+
+  void f4(void *buf, int count, MPI_Datatype datatype)
+       __attribute__(( pointer_with_type_tag(mpi,2,1) )); // expected-error {{attribute is invalid for the implicit this argument}}
+
+  void MPI_Send(void *buf, int count, MPI_Datatype datatype)
+       __attribute__(( pointer_with_type_tag(mpi,2,4) )); // no-error
+};
+
+// Check that we don't crash on type and value dependent expressions.
+template<int a>
+void value_dep(void *buf, int count, MPI_Datatype datatype)
+     __attribute__(( pointer_with_type_tag(mpi,a,5) )); // expected-error {{attribute requires parameter 2 to be an integer constant}}
+
+class OperatorIntStar
+{
+public:
+  operator int*();
+};
+
+void test1(C *c, int *int_buf)
+{
+  c->MPI_Send(int_buf, 1, MPI_INT); // no-warning
+  c->MPI_Send(int_buf, 1, MPI_FLOAT); // expected-warning {{argument type 'int *' doesn't match specified 'mpi' type tag that requires 'float *'}}
+
+  OperatorIntStar i;
+  c->MPI_Send(i, 1, MPI_INT); // no-warning
+  c->MPI_Send(i, 1, MPI_FLOAT); // expected-warning {{argument type 'int *' doesn't match specified 'mpi' type tag that requires 'float *'}}
+}
+
+template<typename T>
+void test2(C *c, int *int_buf, T tag)
+{
+  c->MPI_Send(int_buf, 1, tag); // no-warning
+}
+
+void test3(C *c, int *int_buf) {
+  test2(c, int_buf, MPI_INT);
+  test2(c, int_buf, MPI_NULL);
+}
+





More information about the cfe-commits mailing list