diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index a7680bb..17c9862 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -126,6 +126,11 @@ def AlignMac68k : InheritableAttr {
   let Spellings = [];
 }
 
+def AllocSize : InheritableAttr {
+  let Spellings = ["alloc_size"];
+  let Args = [VariadicUnsignedArgument<"Args">];
+}
+
 def AlwaysInline : InheritableAttr {
   let Spellings = ["always_inline"];
 }
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 4f0eea3..ba9ce26 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1436,6 +1436,8 @@ def err_attribute_requires_objc_interface : Error<
   "attribute may only be applied to an Objective-C interface">;
 def err_attribute_uuid_malformed_guid : Error<
   "uuid attribute contains a malformed GUID">;
+def err_attribute_argument_duplicate: Error<
+  "'%0' attribute parameter %1 is duplicate">;
 def warn_nonnull_pointers_only : Warning<
   "nonnull attribute only applies to pointer arguments">;
 def err_attribute_invalid_implicit_this_argument : Error<
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 545350f..1554d6a 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -165,6 +165,7 @@ public:
     AT_address_space,
     AT_alias,
     AT_aligned,
+    AT_alloc_size,
     AT_always_inline,
     AT_analyzer_noreturn,
     AT_annotate,
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index a3791de..ca055d5 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -114,6 +114,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
     .Case("used", AT_used)
     .Case("alias", AT_alias)
     .Case("align", AT_aligned)
+    .Case("alloc_size", AT_alloc_size)
     .Case("cdecl", AT_cdecl)
     .Case("const", AT_const)
     .Case("__const", AT_const) // some GCC headers do contain this spelling
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index f0830b8..8bce3f3 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -222,6 +222,18 @@ static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr,
   return true;
 }
 
+/// \brief Check if the attribute has no more than Num args. May
+/// output an error.
+static bool checkAttributeNoMoreThanNumArgs(Sema &S, const AttributeList &Attr,
+                                  unsigned int Num) {
+  if (Attr.getNumArgs() > Num) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << Num;
+    return false;
+  }
+
+  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
@@ -1264,6 +1276,78 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D,
   D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context));
 }
 
+static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  // Check the attribute arguments.
+  if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+    return;
+  if (!checkAttributeNoMoreThanNumArgs(S, Attr, 2))
+    return;
+
+  // Count 'this' in C++.
+  bool HasImplicitThisParam = isInstanceMethod(D);
+  unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+
+  SmallVector<unsigned, 2> AllocSizeArgs;
+
+  for (AttributeList::arg_iterator I = Attr.arg_begin(),
+                                   E = Attr.arg_end(); I != E; ++I) {
+
+    // The argument must be an integer constant expression.
+    Expr *E = *I;
+    llvm::APSInt ArgIdx;
+    if (E->isTypeDependent() || E->isValueDependent() ||
+        !E->isIntegerConstantExpr(ArgIdx, S.Context)) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+        << "alloc_size" << E->getSourceRange();
+      return;
+    }
+
+    uint64_t x = ArgIdx.getLimitedValue();
+
+    if (x < 1 || x > NumArgs) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+       << "alloc_size" << I.getArgNum() << E->getSourceRange();
+      return;
+    }
+
+    --x;
+    if (HasImplicitThisParam) {
+      if (x == 0) {
+        S.Diag(Attr.getLoc(),
+               diag::err_attribute_invalid_implicit_this_argument)
+          << "alloc_size" << E->getSourceRange();
+        return;
+      }
+      --x;
+    }
+
+    // Is the function argument an integer type?
+    QualType T = getFunctionOrMethodArgType(D, x);
+    if (!T->isIntegerType()) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+        << "alloc_size" << E->getSourceRange();
+      return;
+    }
+
+    // Is the argument duplicate?
+    SmallVectorImpl<unsigned>::iterator Pos;
+    Pos = std::find(AllocSizeArgs.begin(), AllocSizeArgs.end(), x);
+    if (Pos != AllocSizeArgs.end()) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_duplicate)
+        << "alloc_size" << I.getArgNum() << E->getSourceRange();
+      return;
+    }
+
+    AllocSizeArgs.push_back(x);
+  }
+
+  unsigned* start = &AllocSizeArgs[0];
+  unsigned size = AllocSizeArgs.size();
+  llvm::array_pod_sort(start, start + size);
+  D->addAttr(::new (S.Context) AllocSizeAttr(Attr.getRange(), S.Context,
+                                             start, size));
+}
+
 static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   // Check the attribute arguments.
   if (Attr.hasParameterOrArguments()) {
@@ -3565,6 +3649,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
     break;
   case AttributeList::AT_alias:       handleAliasAttr       (S, D, Attr); break;
   case AttributeList::AT_aligned:     handleAlignedAttr     (S, D, Attr); break;
+  case AttributeList::AT_alloc_size:  handleAllocSizeAttr   (S, D, Attr); break;
   case AttributeList::AT_always_inline:
     handleAlwaysInlineAttr  (S, D, Attr); break;
   case AttributeList::AT_analyzer_noreturn:
diff --git a/test/Sema/attr-alloc_size.c b/test/Sema/attr-alloc_size.c
new file mode 100644
index 0000000..fa8f70e
--- /dev/null
+++ b/test/Sema/attr-alloc_size.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+#include <stddef.h>
+
+void *my_malloc(size_t) __attribute__((alloc_size(1)));
+void *my_calloc(size_t, size_t) __attribute__((alloc_size(1,2)));
+void *my_realloc(void *, size_t) __attribute__((alloc_size(2)));
+
+void *bad_alloc_attr_arg_type(int) __attribute__((alloc_size("dead"))); // \
+// expected-error {{'alloc_size' attribute requires integer constant}}
+
+void *bad_alloc_attr_arg_empty(int) __attribute__((alloc_size)); // \
+// expected-error {{attribute takes at least 1 argument}}
+
+void *bad_alloc_attr_arg_3(int, int, int) __attribute__((alloc_size(1, 2, 3))); // \
+// expected-error {{attribute takes no more than 2 arguments}}
+
+void *bad_alloc_param_index_0(int) __attribute__((alloc_size(0))); // \
+// expected-error {{'alloc_size' attribute parameter 1 is out of bounds}}
+void *bad_alloc_param_index_2(int) __attribute__((alloc_size(2))); // \
+// expected-error {{'alloc_size' attribute parameter 1 is out of bounds}}
+
+void *bad_alloc_param_type(int *) __attribute__((alloc_size(1))); // \
+// expected-error {{'alloc_size' attribute requires integer constant}}
+
+void *bad_alloc_param_dup(int, int) __attribute__((alloc_size(1, 1))); // \
+// expected-error {{'alloc_size' attribute parameter 2 is duplicate}}
