20 changes: 20 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,8 @@ namespace {
QualType ObjectType = QualType(),
NamedDecl *FirstQualifierInScope = nullptr);

const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);

ExprResult TransformPredefinedExpr(PredefinedExpr *E);
ExprResult TransformDeclRefExpr(DeclRefExpr *E);
ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
Expand Down Expand Up @@ -1127,6 +1129,24 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
}

const LoopHintAttr *
TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get();

if (TransformedExpr == LH->getValue())
return LH;

// Generate error if there is a problem with the value.
if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation()))
return LH;

// Create new LoopHintValueAttr with integral expression in place of the
// non-type template parameter.
return LoopHintAttr::CreateImplicit(
getSema().Context, LH->getSemanticSpelling(), LH->getOption(),
LH->getState(), TransformedExpr, LH->getRange());
}

ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
NonTypeTemplateParmDecl *parm,
SourceLocation loc,
Expand Down
59 changes: 52 additions & 7 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,27 @@ class TreeTransform {
/// \returns the transformed OpenMP clause.
OMPClause *TransformOMPClause(OMPClause *S);

/// \brief Transform the given attribute.
///
/// By default, this routine transforms a statement by delegating to the
/// appropriate TransformXXXAttr function to transform a specific kind
/// of attribute. Subclasses may override this function to transform
/// attributed statements using some other mechanism.
///
/// \returns the transformed attribute
const Attr *TransformAttr(const Attr *S);

/// \brief Transform the specified attribute.
///
/// Subclasses should override the transformation of attributes with a pragma
/// spelling to transform expressions stored within the attribute.
///
/// \returns the transformed attribute.
#define ATTR(X)
#define PRAGMA_SPELLING_ATTR(X) \
const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; }
#include "clang/Basic/AttrList.inc"

/// \brief Transform the given expression.
///
/// By default, this routine transforms an expression by delegating to the
Expand Down Expand Up @@ -5543,19 +5564,43 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) {
SubStmt.get());
}

template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
template <typename Derived>
const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) {
if (!R)
return R;

switch (R->getKind()) {
// Transform attributes with a pragma spelling by calling TransformXXXAttr.
#define ATTR(X)
#define PRAGMA_SPELLING_ATTR(X) \
case attr::X: \
return getDerived().Transform##X##Attr(cast<X##Attr>(R));
#include "clang/Basic/AttrList.inc"
default:
return R;
}
}

template <typename Derived>
StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
bool AttrsChanged = false;
SmallVector<const Attr *, 1> Attrs;

// Visit attributes and keep track if any are transformed.
for (const auto *I : S->getAttrs()) {
const Attr *R = getDerived().TransformAttr(I);
AttrsChanged |= (I != R);
Attrs.push_back(R);
}

StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
if (SubStmt.isInvalid())
return StmtError();

// TODO: transform attributes
if (SubStmt.get() == S->getSubStmt() /* && attrs are the same */)
if (SubStmt.get() == S->getSubStmt() && !AttrsChanged)
return S;

return getDerived().RebuildAttributedStmt(S->getAttrLoc(),
S->getAttrs(),
return getDerived().RebuildAttributedStmt(S->getAttrLoc(), Attrs,
SubStmt.get());
}

Expand Down
84 changes: 73 additions & 11 deletions clang/test/CodeGen/pragma-loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ void do_test(int *List, int Length) {
} while (i < Length);
}

enum struct Tuner : short { Interleave = 4, Unroll = 8 };

// Verify for loop is recognized after sequence of pragma clang loop directives.
void for_test(int *List, int Length) {
#pragma clang loop interleave(enable)
#pragma clang loop interleave_count(4)
#pragma clang loop unroll_count(8)
#pragma clang loop interleave_count(static_cast<int>(Tuner::Interleave))
#pragma clang loop unroll_count(static_cast<int>(Tuner::Unroll))
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_3:.*]]
List[i] = i * 2;
Expand Down Expand Up @@ -74,28 +76,74 @@ void for_define_test(int *List, int Length, int Value) {
}
}

// Verify constant expressions are handled correctly.
void for_contant_expression_test(int *List, int Length) {
#pragma clang loop vectorize_width(1 + 4)
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_7:.*]]
List[i] = i;
}

#pragma clang loop vectorize_width(3 + VECWIDTH)
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_8:.*]]
List[i] += i;
}
}

// Verify metadata is generated when template is used.
template <typename A>
void for_template_test(A *List, int Length, A Value) {

#pragma clang loop vectorize_width(8) interleave_count(8) unroll_count(8)
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_7:.*]]
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_9:.*]]
List[i] = i * Value;
}
}

// Verify define is resolved correctly when template is used.
template <typename A>
template <typename A, typename T>
void for_template_define_test(A *List, int Length, A Value) {
#pragma clang loop vectorize_width(VECWIDTH) interleave_count(INTCOUNT)
#pragma clang loop unroll_count(UNROLLCOUNT)
const T VWidth = VECWIDTH;
const T ICount = INTCOUNT;
const T UCount = UNROLLCOUNT;
#pragma clang loop vectorize_width(VWidth) interleave_count(ICount)
#pragma clang loop unroll_count(UCount)
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_8:.*]]
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_10:.*]]
List[i] = i * Value;
}
}

// Verify templates and constant expressions are handled correctly.
template <typename A, int V, int I, int U>
void for_template_constant_expression_test(A *List, int Length) {
#pragma clang loop vectorize_width(V) interleave_count(I) unroll_count(U)
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_11:.*]]
List[i] = i;
}

#pragma clang loop vectorize_width(V * 2 + VECWIDTH) interleave_count(I * 2 + INTCOUNT) unroll_count(U * 2 + UNROLLCOUNT)
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_12:.*]]
List[i] += i;
}

const int Scale = 4;
#pragma clang loop vectorize_width(Scale * V) interleave_count(Scale * I) unroll_count(Scale * U)
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_13:.*]]
List[i] += i;
}

#pragma clang loop vectorize_width((Scale * V) + 2)
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_14:.*]]
List[i] += i;
}
}

#undef VECWIDTH
#undef INTCOUNT
#undef UNROLLCOUNT
Expand All @@ -105,7 +153,8 @@ void template_test(double *List, int Length) {
double Value = 10;

for_template_test<double>(List, Length, Value);
for_template_define_test<double>(List, Length, Value);
for_template_define_test<double, int>(List, Length, Value);
for_template_constant_expression_test<double, 2, 4, 8>(List, Length);
}

// CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata ![[UNROLL_FULL:.*]], metadata ![[WIDTH_4:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[INTENABLE_1:.*]]}
Expand All @@ -124,6 +173,19 @@ void template_test(double *List, int Length) {
// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[UNROLL_DISABLE:.*]], metadata ![[WIDTH_1:.*]]}
// CHECK: ![[WIDTH_1]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 1}
// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata ![[WIDTH_8:.*]]}
// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[WIDTH_5:.*]]}
// CHECK: ![[WIDTH_5]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 5}
// CHECK: ![[LOOP_8]] = metadata !{metadata ![[LOOP_8]], metadata ![[WIDTH_5:.*]]}
// CHECK: ![[LOOP_9]] = metadata !{metadata ![[LOOP_9]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata ![[WIDTH_8:.*]]}
// CHECK: ![[INTERLEAVE_8]] = metadata !{metadata !"llvm.loop.interleave.count", i32 8}
// CHECK: ![[LOOP_8]] = metadata !{metadata ![[LOOP_8]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
// CHECK: ![[LOOP_10]] = metadata !{metadata ![[LOOP_10]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
// CHECK: ![[LOOP_11]] = metadata !{metadata ![[LOOP_11]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[WIDTH_2:.*]]}
// CHECK: ![[LOOP_12]] = metadata !{metadata ![[LOOP_12]], metadata ![[UNROLL_24:.*]], metadata ![[INTERLEAVE_10:.*]], metadata ![[WIDTH_6:.*]]}
// CHECK: ![[UNROLL_24]] = metadata !{metadata !"llvm.loop.unroll.count", i32 24}
// CHECK: ![[INTERLEAVE_10]] = metadata !{metadata !"llvm.loop.interleave.count", i32 10}
// CHECK: ![[WIDTH_6]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 6}
// CHECK: ![[LOOP_13]] = metadata !{metadata ![[LOOP_13]], metadata ![[UNROLL_32:.*]], metadata ![[INTERLEAVE_16:.*]], metadata ![[WIDTH_8:.*]]}
// CHECK: ![[UNROLL_32]] = metadata !{metadata !"llvm.loop.unroll.count", i32 32}
// CHECK: ![[INTERLEAVE_16]] = metadata !{metadata !"llvm.loop.interleave.count", i32 16}
// CHECK: ![[LOOP_14]] = metadata !{metadata ![[LOOP_14]], metadata ![[WIDTH_10:.*]]}
// CHECK: ![[WIDTH_10]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 10}
15 changes: 15 additions & 0 deletions clang/test/Misc/ast-print-pragmas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,18 @@ void test(int *List, int Length) {
i++;
}
}

template <int V, int I>
void test_nontype_template_param(int *List, int Length) {
#pragma clang loop vectorize_width(V) interleave_count(I)
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}

// CHECK: #pragma clang loop interleave_count(I)
// CHECK: #pragma clang loop vectorize_width(V)

void test_templates(int *List, int Length) {
test_nontype_template_param<2, 4>(List, Length);
}
12 changes: 12 additions & 0 deletions clang/test/PCH/pragma-loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// CHECK: #pragma unroll
// CHECK: #pragma unroll (32)
// CHECK: #pragma nounroll
// CHECK: #pragma clang loop interleave_count(I)
// CHECK: #pragma clang loop vectorize_width(V)

#ifndef HEADER
#define HEADER
Expand Down Expand Up @@ -81,6 +83,15 @@ class pragma_test {
i++;
}
}

template <int V, int I>
inline void run7(int *List, int Length) {
#pragma clang loop vectorize_width(V)
#pragma clang loop interleave_count(I)
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}
};
#else

Expand All @@ -95,6 +106,7 @@ void test() {
pt.run4(List, 100);
pt.run5(List, 100);
pt.run6(List, 100);
pt.run7<2, 4>(List, 100);
}

#endif
129 changes: 110 additions & 19 deletions clang/test/Parser/pragma-loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,79 @@
// Note that this puts the expected lines before the directives to work around
// limitations in the -verify mode.

template <int V, int I>
void test_nontype_template_param(int *List, int Length) {
#pragma clang loop vectorize_width(V) interleave_count(I)
for (int i = 0; i < Length; i++) {
List[i] = i;
}

#pragma clang loop vectorize_width(V + 4) interleave_count(I + 4)
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}

template <int V>
void test_nontype_template_vectorize(int *List, int Length) {
/* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop vectorize_width(V)
for (int i = 0; i < Length; i++) {
List[i] = i;
}

/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop vectorize_width(V / 2)
for (int i = 0; i < Length; i++) {
List[i] += i;
}
}

template <int I>
void test_nontype_template_interleave(int *List, int Length) {
/* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop interleave_count(I)
for (int i = 0; i < Length; i++) {
List[i] = i;
}

/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(2 % I)
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}

template <char V>
void test_nontype_template_char(int *List, int Length) {
/* expected-error {{invalid argument of type 'char'; expected an integer type}} */ #pragma clang loop vectorize_width(V)
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}

template <bool V>
void test_nontype_template_bool(int *List, int Length) {
/* expected-error {{invalid argument of type 'bool'; expected an integer type}} */ #pragma clang loop vectorize_width(V)
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}

template <int V, int I>
void test_nontype_template_badarg(int *List, int Length) {
/* expected-error {{use of undeclared identifier 'Vec'}} */ #pragma clang loop vectorize_width(Vec) interleave_count(I)
/* expected-error {{use of undeclared identifier 'Int'}} */ #pragma clang loop vectorize_width(V) interleave_count(Int)
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}

template <typename T>
void test_type_template_vectorize(int *List, int Length) {
const T Value = -1;
/* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop vectorize_width(Value)
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}

void test(int *List, int Length) {
int i = 0;

Expand Down Expand Up @@ -43,6 +116,8 @@ void test(int *List, int Length) {
VList[j] = List[j];
}

test_nontype_template_param<4, 8>(List, Length);

/* expected-error {{expected '('}} */ #pragma clang loop vectorize
/* expected-error {{expected '('}} */ #pragma clang loop interleave
/* expected-error {{expected '('}} */ #pragma clang loop unroll
Expand All @@ -55,40 +130,56 @@ void test(int *List, int Length) {
/* expected-error {{expected ')'}} */ #pragma clang loop interleave_count(4
/* expected-error {{expected ')'}} */ #pragma clang loop unroll_count(4

/* expected-error {{missing argument to '#pragma clang loop vectorize'}} */ #pragma clang loop vectorize()
/* expected-error {{missing argument to '#pragma clang loop interleave_count'}} */ #pragma clang loop interleave_count()
/* expected-error {{missing argument to '#pragma clang loop unroll'}} */ #pragma clang loop unroll()
/* expected-error {{missing argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize()
/* expected-error {{missing argument; expected an integer value}} */ #pragma clang loop interleave_count()
/* expected-error {{missing argument; expected 'enable' or 'disable'}} */ #pragma clang loop unroll()

/* expected-error {{missing option}} */ #pragma clang loop
/* expected-error {{missing option; expected vectorize, vectorize_width, interleave, interleave_count, unroll, or unroll_count}} */ #pragma clang loop
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword(enable)
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop vectorize(enable) badkeyword(4)
/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize(enable) ,

while (i-4 < Length) {
List[i] = i;
}

/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(0)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(0)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(0)
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop vectorize_width(0)
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(0)
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop unroll_count(0)

/* expected-error {{expression is not an integral constant expression}} expected-note {{division by zero}} */ #pragma clang loop vectorize_width(10 / 0)
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(10 / 5 - 2)
while (i-5 < Length) {
List[i] = i;
}

/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(3000000000)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(3000000000)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(3000000000)
test_nontype_template_vectorize<4>(List, Length);
/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_vectorize<-1>(List, Length);
test_nontype_template_interleave<8>(List, Length);
/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_interleave<-1>(List, Length);

/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_char<'A'>(List, Length); // Loop hint arg cannot be a char.
/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_bool<true>(List, Length); // Or a bool.
/* expected-note {{in instantiation of function template specialization}} */ test_type_template_vectorize<int>(List, Length); // Or a template type.

/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop vectorize_width(3000000000)
/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop interleave_count(3000000000)
/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop unroll_count(3000000000)
while (i-6 < Length) {
List[i] = i;
}

/* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(1 +) 1
/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize_width(1 +) 1
/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize_width(1) +1
const int VV = 4;
/* expected-error {{expected expression}} */ #pragma clang loop vectorize_width(VV +/ 2)
/* expected-error {{use of undeclared identifier 'undefined'}} */ #pragma clang loop vectorize_width(VV+undefined)
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(1+(^*/2 * ()
/* expected-warning {{extra tokens at end of '#pragma clang loop' - ignored}} */ #pragma clang loop vectorize_width(1+(-0[0]))))))

/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(badvalue)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(badvalue)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(badvalue)
/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop vectorize_width(badvalue)
/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop interleave_count(badvalue)
/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop unroll_count(badvalue)
while (i-6 < Length) {
List[i] = i;
}
Expand All @@ -102,12 +193,12 @@ void test(int *List, int Length) {

// PR20069 - Loop pragma arguments that are not identifiers or numeric
// constants crash FE.
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize(()
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize(()
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop interleave(*)
/* expected-error {{invalid argument; expected 'full' or 'disable'}} */ #pragma clang loop unroll(=)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(^)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(/)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(==)
/* expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}} */ #pragma clang loop vectorize_width(^)
/* expected-error {{expected expression}} expected-error {{expected expression}} */ #pragma clang loop interleave_count(/)
/* expected-error {{expected expression}} expected-error {{expected expression}} */ #pragma clang loop unroll_count(==)
while (i-8 < Length) {
List[i] = i;
}
Expand Down
14 changes: 7 additions & 7 deletions clang/test/Parser/pragma-unroll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void test(int *List, int Length) {
}

/* expected-error {{expected ')'}} */ #pragma unroll(4
/* expected-error {{missing argument to '#pragma unroll'}} */ #pragma unroll()
/* expected-error {{missing argument; expected an integer value}} */ #pragma unroll()
/* expected-warning {{extra tokens at end of '#pragma unroll'}} */ #pragma unroll 1 2
while (i-6 < Length) {
List[i] = i;
Expand All @@ -38,12 +38,12 @@ void test(int *List, int Length) {
List[i] = i;
}

/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(()
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll -
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(0)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 0
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(3000000000)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 3000000000
/* expected-error {{expected ')'}} */ #pragma unroll(()
/* expected-error {{expected expression}} */ #pragma unroll -
/* expected-error {{invalid value '0'; must be positive}} */ #pragma unroll(0)
/* expected-error {{invalid value '0'; must be positive}} */ #pragma unroll 0
/* expected-error {{value '3000000000' is too large}} */ #pragma unroll(3000000000)
/* expected-error {{value '3000000000' is too large}} */ #pragma unroll 3000000000
while (i-8 < Length) {
List[i] = i;
}
Expand Down
30 changes: 26 additions & 4 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1669,8 +1669,16 @@ static void EmitAttrList(raw_ostream &OS, StringRef Class,
}
}

namespace clang {
// Determines if an attribute has a Pragma spelling.
static bool AttrHasPragmaSpelling(const Record *R) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
return std::find_if(Spellings.begin(), Spellings.end(),
[](const FlattenedSpelling &S) {
return S.variety() == "Pragma";
}) != Spellings.end();
}

namespace clang {
// Emits the enumeration list for attributes.
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
Expand All @@ -1696,14 +1704,25 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
" INHERITABLE_PARAM_ATTR(NAME)\n";
OS << "#endif\n\n";

OS << "#ifndef PRAGMA_SPELLING_ATTR\n";
OS << "#define PRAGMA_SPELLING_ATTR(NAME)\n";
OS << "#endif\n\n";

OS << "#ifndef LAST_PRAGMA_SPELLING_ATTR\n";
OS << "#define LAST_PRAGMA_SPELLING_ATTR(NAME) PRAGMA_SPELLING_ATTR(NAME)\n";
OS << "#endif\n\n";

Record *InhClass = Records.getClass("InheritableAttr");
Record *InhParamClass = Records.getClass("InheritableParamAttr");
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
NonInhAttrs, InhAttrs, InhParamAttrs;
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"),
NonInhAttrs, InhAttrs, InhParamAttrs, PragmaAttrs;
for (auto *Attr : Attrs) {
if (!Attr->getValueAsBit("ASTNode"))
continue;


if (AttrHasPragmaSpelling(Attr))
PragmaAttrs.push_back(Attr);

if (Attr->isSubClassOf(InhParamClass))
InhParamAttrs.push_back(Attr);
else if (Attr->isSubClassOf(InhClass))
Expand All @@ -1712,6 +1731,7 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
NonInhAttrs.push_back(Attr);
}

EmitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs);
EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);
EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);
EmitAttrList(OS, "ATTR", NonInhAttrs);
Expand All @@ -1720,6 +1740,8 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#undef INHERITABLE_ATTR\n";
OS << "#undef LAST_INHERITABLE_ATTR\n";
OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n";
OS << "#undef LAST_PRAGMA_ATTR\n";
OS << "#undef PRAGMA_SPELLING_ATTR\n";
OS << "#undef ATTR\n";
}

Expand Down