erichkeane updated this revision to Diff 92814.
erichkeane added a comment.

Update test based on the corresponding LLVM change.


https://reviews.llvm.org/D29599

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Sema/Sema.h
  lib/CodeGen/CGCall.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/CodeGen/alloc-align-attr.c
  test/Sema/alloc-align-attr.c
  test/SemaCXX/alloc-align-attr.cpp

Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -4370,7 +4370,11 @@
       llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(Alignment);
       EmitAlignmentAssumption(Ret.getScalarVal(), AlignmentCI->getZExtValue(),
                               OffsetValue);
+    } else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) {
+      llvm::Value *ParamVal = IRCallArgs[AA->getParamIndex() - 1];
+      EmitAlignmentAssumption(Ret.getScalarVal(), ParamVal);
     }
+
   }
 
   return Ret;
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -2465,6 +2465,12 @@
   PeepholeProtection protectFromPeepholes(RValue rvalue);
   void unprotectFromPeepholes(PeepholeProtection protection);
 
+  void EmitAlignmentAssumption(llvm::Value *PtrValue, llvm::Value *Alignment,
+                               llvm::Value *OffsetValue = nullptr) {
+    Builder.CreateAlignmentAssumption(CGM.getDataLayout(), PtrValue, Alignment,
+                                      OffsetValue);
+  }
+
   //===--------------------------------------------------------------------===//
   //                             Statement Emission
   //===--------------------------------------------------------------------===//
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -168,6 +168,16 @@
                         Aligned->getSpellingListIndex());
 }
 
+static void instantiateDependentAllocAlignAttr(
+    Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+    const AllocAlignAttr *Align, Decl *New) {
+  Expr *Param = IntegerLiteral::Create(
+      S.getASTContext(), llvm::APInt(64, Align->getParamIndex()),
+      S.getASTContext().UnsignedLongLongTy, Align->getLocation());
+  S.AddAllocAlignAttr(Align->getLocation(), New, Param,
+                      Align->getSpellingListIndex());
+}
+
 static Expr *instantiateDependentFunctionAttrCondition(
     Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
     const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) {
@@ -352,6 +362,12 @@
       continue;
     }
 
+    if (const auto *AllocAlign = dyn_cast<AllocAlignAttr>(TmplAttr)) {
+      instantiateDependentAllocAlignAttr(*this, TemplateArgs, AllocAlign, New);
+      continue;
+    }
+
+
     if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
       instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
                                        cast<FunctionDecl>(New));
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -218,21 +218,42 @@
                                    std::greater<unsigned>());
 }
 
+/// \brief A helper function to provide Attribute Location for the Attr types
+/// AND the AttributeList
+template <class AttrInfo> static typename
+std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, SourceLocation>::type
+getAttrLoc(const AttrInfo& Attr) {
+  return Attr.getLocation();
+}
+static SourceLocation getAttrLoc(const clang::AttributeList& Attr) {
+  return Attr.getLoc();
+}
+/// \brief A helper function to provide Attribute Name for the Attr types
+/// AND the AttributeList
+template <class AttrInfo> static typename
+std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, const AttrInfo*>::type
+getAttrName(const AttrInfo& Attr) {
+  return &Attr;
+}
+const IdentifierInfo* getAttrName(const clang::AttributeList &Attr) {
+  return Attr.getName();
+}
+
 /// \brief If Expr is a valid integer constant, get the value of the integer
 /// expression and return success or failure. May output an error.
-static bool checkUInt32Argument(Sema &S, const AttributeList &Attr,
-                                const Expr *Expr, uint32_t &Val,
-                                unsigned Idx = UINT_MAX) {
+template<typename AttrInfo>
+static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr,
+                                uint32_t &Val, unsigned Idx = UINT_MAX) {
   llvm::APSInt I(32);
   if (Expr->isTypeDependent() || Expr->isValueDependent() ||
       !Expr->isIntegerConstantExpr(I, S.Context)) {
     if (Idx != UINT_MAX)
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
-        << Attr.getName() << Idx << AANT_ArgumentIntegerConstant
+      S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type)
+        << getAttrName(Attr) << Idx << AANT_ArgumentIntegerConstant
         << Expr->getSourceRange();
     else
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
-        << Attr.getName() << AANT_ArgumentIntegerConstant
+      S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_type)
+        << getAttrName(Attr) << AANT_ArgumentIntegerConstant
         << Expr->getSourceRange();
     return false;
   }
@@ -250,9 +271,9 @@
 /// \brief Wrapper around checkUInt32Argument, with an extra check to be sure
 /// that the result will fit into a regular (signed) int. All args have the same
 /// purpose as they do in checkUInt32Argument.
-static bool checkPositiveIntArgument(Sema &S, const AttributeList &Attr,
-                                     const Expr *Expr, int &Val,
-                                     unsigned Idx = UINT_MAX) {
+template<typename AttrInfo>
+static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr *Expr,
+                                     int &Val, unsigned Idx = UINT_MAX) {
   uint32_t UVal;
   if (!checkUInt32Argument(S, Attr, Expr, UVal, Idx))
     return false;
@@ -287,11 +308,10 @@
 /// instance method D.  May output an error.
 ///
 /// \returns true if IdxExpr is a valid index.
-static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D,
-                                                const AttributeList &Attr,
-                                                unsigned AttrArgNum,
-                                                const Expr *IdxExpr,
-                                                uint64_t &Idx) {
+template <typename AttrInfo>
+static bool checkFunctionOrMethodParameterIndex(
+    Sema &S, const Decl *D, const AttrInfo& Attr,
+    unsigned AttrArgNum, const Expr *IdxExpr, uint64_t &Idx) {
   assert(isFunctionOrMethodOrBlock(D));
 
   // In C++ the implicit 'this' function parameter also counts.
@@ -305,24 +325,24 @@
   llvm::APSInt IdxInt;
   if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
       !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
-      << Attr.getName() << AttrArgNum << AANT_ArgumentIntegerConstant
+    S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type)
+      << getAttrName(Attr) << AttrArgNum << AANT_ArgumentIntegerConstant
       << IdxExpr->getSourceRange();
     return false;
   }
 
   Idx = IdxInt.getLimitedValue();
   if (Idx < 1 || (!IV && Idx > NumParams)) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
-      << Attr.getName() << AttrArgNum << IdxExpr->getSourceRange();
+    S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_out_of_bounds)
+      << getAttrName(Attr) << AttrArgNum << IdxExpr->getSourceRange();
     return false;
   }
   Idx--; // Convert to zero-based.
   if (HasImplicitThisParam) {
     if (Idx == 0) {
-      S.Diag(Attr.getLoc(),
+      S.Diag(getAttrLoc(Attr),
              diag::err_attribute_invalid_implicit_this_argument)
-        << Attr.getName() << IdxExpr->getSourceRange();
+        << getAttrName(Attr) << IdxExpr->getSourceRange();
       return false;
     }
     --Idx;
@@ -752,32 +772,51 @@
                                      StartArg, Size,
                                      Attr.getAttributeSpellingListIndex()));
 }
-
+//
 /// \brief Checks to be sure that the given parameter number is inbounds, and is
 /// an some integral type. Will emit appropriate diagnostics if this returns
 /// false.
 ///
 /// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used
 /// to actually retrieve the argument, so it's base-0.
+template <typename AttrInfo>
 static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
-                                    const AttributeList &Attr,
-                                    unsigned FuncParamNo, unsigned AttrArgNo) {
-  assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument");
+                                    const AttrInfo &Attr, Expr *AttrArg,
+                                    unsigned FuncParamNo, unsigned AttrArgNo,
+                                    bool AllowDependentType = false) {
   uint64_t Idx;
-  if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo,
-                                           Attr.getArgAsExpr(AttrArgNo), Idx))
+  if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, AttrArg,
+                                           Idx))
     return false;
 
   const ParmVarDecl *Param = FD->getParamDecl(Idx);
+  if (AllowDependentType && Param->getType()->isDependentType()) {
+    return true;
+  }
   if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) {
-    SourceLocation SrcLoc = Attr.getArgAsExpr(AttrArgNo)->getLocStart();
+    SourceLocation SrcLoc = AttrArg->getLocStart();
     S.Diag(SrcLoc, diag::err_attribute_integers_only)
-        << Attr.getName() << Param->getSourceRange();
+        << getAttrName(Attr) << Param->getSourceRange();
     return false;
   }
   return true;
 }
 
+/// \brief Checks to be sure that the given parameter number is inbounds, and is
+/// an some integral type. Will emit appropriate diagnostics if this returns
+/// false.
+///
+/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used
+/// to actually retrieve the argument, so it's base-0.
+static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
+                                    const AttributeList &Attr,
+                                    unsigned FuncParamNo, unsigned AttrArgNo,
+                                    bool AllowDependentType = false) {
+  assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument");
+  return checkParamIsIntegerType(S, FD, Attr, Attr.getArgAsExpr(AttrArgNo),
+                                 FuncParamNo, AttrArgNo, AllowDependentType);
+}
+
 static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   if (!checkAttributeAtLeastNumArgs(S, Attr, 1) ||
       !checkAttributeAtMostNumArgs(S, Attr, 2))
@@ -1484,6 +1523,13 @@
                          Attr.getAttributeSpellingListIndex());
 }
 
+static void handleAllocAlignAttr(Sema &S, Decl *D,
+                                   const AttributeList &Attr) {
+  Expr *E = Attr.getArgAsExpr(0);
+  S.AddAllocAlignAttr(Attr.getRange(), D, E, 
+                       Attr.getAttributeSpellingListIndex());
+}
+
 void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
                                 Expr *OE, unsigned SpellingListIndex) {
   QualType ResultType = getFunctionOrMethodResultType(D);
@@ -1535,6 +1581,34 @@
             AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex));
 }
 
+void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
+                             unsigned SpellingListIndex) {
+  QualType ResultType = getFunctionOrMethodResultType(D);
+
+  AllocAlignAttr TmpAttr(AttrRange, Context, 0, SpellingListIndex);
+  SourceLocation AttrLoc = AttrRange.getBegin();
+
+  if (!ResultType->isDependentType() &&
+      !isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
+    Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
+        << &TmpAttr << AttrRange << getFunctionOrMethodResultSourceRange(D);
+    return;
+  }
+
+  int IndexVal;
+  if (!checkPositiveIntArgument(*this, TmpAttr, ParamExpr, IndexVal,
+                                /*Index=*/1))
+    return;
+
+  const auto *FuncDecl = cast<FunctionDecl>(D);
+  if (!checkParamIsIntegerType(*this, FuncDecl, TmpAttr, ParamExpr, IndexVal,
+                               /*AttrArgNo=*/0, /*AllowDependentType=*/true))
+    return;
+
+  D->addAttr(::new (Context) AllocAlignAttr(AttrRange, Context, IndexVal,
+                                            SpellingListIndex));
+}
+
 /// Normalize the attribute, __foo__ becomes foo.
 /// Returns true if normalization was applied.
 static bool normalizeName(StringRef &AttrName) {
@@ -5937,6 +6011,9 @@
   case AttributeList::AT_AssumeAligned:
     handleAssumeAlignedAttr(S, D, Attr);
     break;
+  case AttributeList::AT_AllocAlign:
+    handleAllocAlignAttr(S, D, Attr);
+    break;
   case AttributeList::AT_Overloadable:
     handleSimpleAttribute<OverloadableAttr>(S, D, Attr);
     break;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -8172,6 +8172,11 @@
   void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE,
                             unsigned SpellingListIndex);
 
+  /// AddAllocAlignAttr - Adds an alloc_align attribute to a particular
+  /// declaration.
+  void AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
+                         unsigned SpellingListIndex);
+
   /// AddAlignValueAttr - Adds an align_value attribute to a particular
   /// declaration.
   void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -244,6 +244,27 @@
   }];
 }
 
+def AllocAlignDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+Use ``__attribute__((alloc_align(<alignment>))`` on a function
+declaration to specify that the return value of the function (which must be a
+pointer type) has an alignment specified by the indicated parameter, starting
+with 1.
+
+.. code-block:: c++
+  // The returned pointer has the alignment specified by the first parameter
+  void *a(size_t align) __attribute__((alloc_align(1)));
+
+  // The returned pointer has the alignment specified by the second parameter
+  void *b(void* v, size_t align) __attribute__((alloc_align(2)));
+
+Note that this attribute provides information to the compiler regarding a
+condition that the code already ensures is true. It does not cause the compiler
+to enforce the provided alignment assumption.
+  }];
+}
+
 def EnableIfDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1220,6 +1220,13 @@
   let Documentation = [AssumeAlignedDocs];
 }
 
+def AllocAlign : InheritableAttr {
+  let Spellings = [ GCC<"alloc_align"> ];
+  let Subjects = SubjectList<[Function]>;
+  let Args = [ IntArgument<"ParamIndex"> ];
+  let Documentation = [ AllocAlignDocs ];
+}
+
 def NoReturn : InheritableAttr {
   let Spellings = [GCC<"noreturn">, Declspec<"noreturn">];
   // FIXME: Does GCC allow this on the function instead?
Index: test/SemaCXX/alloc-align-attr.cpp
===================================================================
--- test/SemaCXX/alloc-align-attr.cpp
+++ test/SemaCXX/alloc-align-attr.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct param_num {
+  void* Foo(int a) __attribute__((alloc_align(1))); // expected-error {{'alloc_align' attribute is invalid for the implicit this argument}}
+};
+
+template <typename T>
+struct dependent_ret {
+  T* Foo(int a) __attribute__((alloc_align(2)));// no-warning, ends up being int**.
+  T Foo2(int a) __attribute__((alloc_align(2)));// expected-warning {{'alloc_align' attribute only applies to return values that are pointers or references}}
+
+};
+
+// Following 2 errors associated only with the 'float' versions below.
+template <typename T>
+struct dependent_param_struct {
+  void* Foo(T param) __attribute__((alloc_align(2))); // expected-error {{'alloc_align' attribute argument may only refer to a function parameter of integer type}}
+};
+
+template <typename T>
+void* dependent_param_func(T param) __attribute__((alloc_align(1)));// expected-error {{'alloc_align' attribute argument may only refer to a function parameter of integer type}}
+
+
+template <int T>
+void* illegal_align_param(int p) __attribute__((alloc_align(T))); // expected-error {{'alloc_align' attribute requires parameter 1 to be an integer constant}}
+
+void dependent_impl() {
+  dependent_ret<int> a; // expected-note {{in instantiation of template class 'dependent_ret<int>' requested here}}
+  a.Foo(1);
+  a.Foo2(1);
+  dependent_ret<int*> b; 
+  a.Foo(1);
+  a.Foo2(1);
+
+  dependent_param_struct<int> c; 
+  c.Foo(1);
+  dependent_param_struct<float> d; // expected-note {{in instantiation of template class 'dependent_param_struct<float>' requested here}}
+  d.Foo(1.0);
+  dependent_param_func<int>(1);
+  dependent_param_func<float>(1); // expected-note {{in instantiation of function template specialization 'dependent_param_func<float>' requested here}}
+}
Index: test/CodeGen/alloc-align-attr.c
===================================================================
--- test/CodeGen/alloc-align-attr.c
+++ test/CodeGen/alloc-align-attr.c
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+__INT32_TYPE__*m1(__INT32_TYPE__ i) __attribute__((alloc_align(1)));
+
+// Condition where parameter to m1 is not size_t.
+__INT32_TYPE__ test1(__INT32_TYPE__ a) {
+// CHECK: define i32 @test1
+  return *m1(a);
+// CHECK: call i32* @m1(i32 [[PARAM1:%[^\)]+]]) 
+// CHECK: [[ALIGNCAST1:%.+]] = sext i32 [[PARAM1]] to i64
+// CHECK: [[ISPOS1:%.+]] = icmp sgt i64 [[ALIGNCAST1]], 0
+// CHECK: [[POSMASK1:%.+]] = sub i64 [[ALIGNCAST1]], 1
+// CHECK: [[MASK1:%.+]] = select i1 [[ISPOS1]], i64 [[POSMASK1]], i64 0
+// CHECK: [[PTRINT1:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR1:%.+]] = and i64 [[PTRINT1]], [[MASK1]]
+// CHECK: [[MASKCOND1:%.+]] = icmp eq i64 [[MASKEDPTR1]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND1]])
+}
+// Condition where test2 param needs casting.
+__INT32_TYPE__ test2(__SIZE_TYPE__ a) {
+// CHECK: define i32 @test2
+  return *m1(a);
+// CHECK: [[CONV2:%.+]] = trunc i64 %{{.+}} to i32
+// CHECK: call i32* @m1(i32 [[CONV2]])
+// CHECK: [[ALIGNCAST2:%.+]] = sext i32 [[CONV2]] to i64
+// CHECK: [[ISPOS2:%.+]] = icmp sgt i64 [[ALIGNCAST2]], 0
+// CHECK: [[POSMASK2:%.+]] = sub i64 [[ALIGNCAST2]], 1
+// CHECK: [[MASK2:%.+]] = select i1 [[ISPOS2]], i64 [[POSMASK2]], i64 0
+// CHECK: [[PTRINT2:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR2:%.+]] = and i64 [[PTRINT2]], [[MASK2]]
+// CHECK: [[MASKCOND2:%.+]] = icmp eq i64 [[MASKEDPTR2]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND2]])
+}
+__INT32_TYPE__ *m2(__SIZE_TYPE__ i) __attribute__((alloc_align(1)));
+
+// test3 param needs casting, but 'm2' is correct.
+__INT32_TYPE__ test3(__INT32_TYPE__ a) {
+// CHECK: define i32 @test3
+  return *m2(a);
+// CHECK: [[CONV3:%.+]] = sext i32 %{{.+}} to i64
+// CHECK: call i32* @m2(i64 [[CONV3]])
+// CHECK: [[ISPOS3:%.+]] = icmp sgt i64 [[CONV3]], 0
+// CHECK: [[POSMASK3:%.+]] = sub i64 [[CONV3]], 1
+// CHECK: [[MASK3:%.+]] = select i1 [[ISPOS3]], i64 [[POSMASK3]], i64 0
+// CHECK: [[PTRINT3:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR3:%.+]] = and i64 [[PTRINT3]], [[MASK3]]
+// CHECK: [[MASKCOND3:%.+]] = icmp eq i64 [[MASKEDPTR3]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND3]])
+}
+
+// Every type matches, canonical example.
+__INT32_TYPE__ test4(__SIZE_TYPE__ a) {
+// CHECK: define i32 @test4
+  return *m2(a);
+// CHECK: call i32* @m2(i64 [[PARAM4:%[^\)]+]]) 
+// CHECK: [[ISPOS4:%.+]] = icmp sgt i64 [[PARAM4]], 0
+// CHECK: [[POSMASK4:%.+]] = sub i64 [[PARAM4]], 1
+// CHECK: [[MASK4:%.+]] = select i1 [[ISPOS4]], i64 [[POSMASK4]], i64 0
+// CHECK: [[PTRINT4:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR4:%.+]] = and i64 [[PTRINT4]], [[MASK4]]
+// CHECK: [[MASKCOND4:%.+]] = icmp eq i64 [[MASKEDPTR4]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND4]])
+}
Index: test/Sema/alloc-align-attr.c
===================================================================
--- test/Sema/alloc-align-attr.c
+++ test/Sema/alloc-align-attr.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// return values
+void test_void_alloc_align(void) __attribute__((alloc_align(1))); // expected-warning {{'alloc_align' attribute only applies to return values that are pointers}}
+int test_int_alloc_align(void) __attribute__((alloc_align(1))); // expected-warning {{'alloc_align' attribute only applies to return values that are pointers}}
+void *test_ptr_alloc_align(int a) __attribute__((alloc_align(1))); // no-warning
+
+int j __attribute__((alloc_align(1))); // expected-warning {{'alloc_align' attribute only applies to functions}}
+void *test_no_params_zero() __attribute__((alloc_align(0))); // expected-error {{'alloc_align' attribute parameter 0 is out of bounds}}
+void *test_no_params() __attribute__((alloc_align(1))); // expected-error {{'alloc_align' attribute parameter 1 is out of bounds}}
+void *test_insufficient_params(int a) __attribute__((alloc_align(2))); // expected-error {{'alloc_align' attribute parameter 2 is out of bounds}}
+void *test_incorrect_param_type(float a) __attribute__((alloc_align(1))); // expected-error {{'alloc_align' attribute argument may only refer to a function parameter of integer type}}
+
+// argument type
+void *test_bad_param_type(void) __attribute((alloc_align(1.1))); // expected-error {{'alloc_align' attribute requires parameter 1 to be an integer constant}}
+void *test_bad_param_type(void) __attribute((alloc_align("Foo"))); // expected-error {{'alloc_align' attribute requires parameter 1 to be an integer constant}}
+
+// argument count
+void *test_no_fn_proto() __attribute__((alloc_align)); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto() __attribute__((alloc_align())); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto() __attribute__((alloc_align(32, 45, 37))); // expected-error {{'alloc_align' attribute takes one argument}}
+
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to