r219589 - Allow constant expressions in pragma loop hints.

Tyler Nowicki tyler.nowicki at gmail.com
Sun Oct 12 13:46:08 PDT 2014


Author: tnowicki
Date: Sun Oct 12 15:46:07 2014
New Revision: 219589

URL: http://llvm.org/viewvc/llvm-project?rev=219589&view=rev
Log:
Allow constant expressions in pragma loop hints.

Previously loop hints such as #pragma loop vectorize_width(#) required a constant. This patch allows a constant expression to be used as well. Such as a non-type template parameter or an expression (2 * c + 1).

Reviewed by Richard Smith

Modified:
    cfe/trunk/include/clang/AST/Attr.h
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/Parse/ParsePragma.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaStmtAttr.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/CodeGen/pragma-loop.cpp
    cfe/trunk/test/Misc/ast-print-pragmas.cpp
    cfe/trunk/test/PCH/pragma-loop.cpp
    cfe/trunk/test/Parser/pragma-loop.cpp
    cfe/trunk/test/Parser/pragma-unroll.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Modified: cfe/trunk/include/clang/AST/Attr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Attr.h (original)
+++ cfe/trunk/include/clang/AST/Attr.h Sun Oct 12 15:46:07 2014
@@ -16,6 +16,7 @@
 
 #include "clang/AST/AttrIterator.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/AttrKinds.h"
 #include "clang/Basic/LLVM.h"

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Sun Oct 12 15:46:07 2014
@@ -1845,7 +1845,7 @@ def LoopHint : Attr {
               EnumArgument<"State", "LoopHintState",
                            ["default", "enable", "disable"],
                            ["Default", "Enable", "Disable"]>,
-              DefaultIntArgument<"Value", 1>];
+              ExprArgument<"Value">];
 
   let AdditionalMembers = [{
   static const char *getOptionName(int Option) {
@@ -1885,7 +1885,7 @@ def LoopHint : Attr {
     OS << "(";
     if (option == VectorizeWidth || option == InterleaveCount ||
         option == UnrollCount)
-      OS << value;
+      value->printPretty(OS, nullptr, Policy);
     else if (state == Default)
       return "";
     else if (state == Enable)

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Sun Oct 12 15:46:07 2014
@@ -949,16 +949,15 @@ def err_omp_immediate_directive : Error<
 def err_omp_expected_identifier_for_critical : Error<
   "expected identifier specifying the name of the 'omp critical' directive">;
 
-// Pragma support.
-def err_pragma_invalid_keyword : Error<
-  "%select{invalid|missing}0 argument; expected '%select{enable|full}1' or 'disable'">;
-
 // Pragma loop support.
+def err_pragma_loop_missing_argument : Error<
+  "missing argument; expected %select{an integer value|"
+  "'%select{enable|full}1' or 'disable'}0">;
 def err_pragma_loop_invalid_option : Error<
   "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
   "vectorize_width, interleave, interleave_count, unroll, or unroll_count">;
-def err_pragma_loop_numeric_value : Error<
-  "invalid argument; expected a positive integer value">;
+def err_pragma_invalid_keyword : Error<
+  "invalid argument; expected '%select{enable|full}0' or 'disable'">;
 
 // Pragma unroll support.
 def warn_pragma_unroll_cuda_value_in_parens : Warning<

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Oct 12 15:46:07 2014
@@ -551,8 +551,10 @@ def err_pragma_pop_visibility_mismatch :
   "#pragma visibility pop with no matching #pragma visibility push">;
 def note_surrounding_namespace_starts_here : Note<
   "surrounding namespace with visibility attribute starts here">;
-def err_pragma_loop_invalid_value : Error<
-  "invalid argument; expected a positive integer value">;
+def err_pragma_loop_invalid_argument_type : Error<
+  "invalid argument of type %0; expected an integer type">;
+def err_pragma_loop_invalid_argument_value : Error<
+  "%select{invalid value '%0'; must be positive|value '%0' is too large}1">;
 def err_pragma_loop_compatibility : Error<
   "%select{incompatible|duplicate}0 directives '%1' and '%2'">;
 def err_pragma_loop_precedes_nonloop : Error<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sun Oct 12 15:46:07 2014
@@ -3486,6 +3486,9 @@ public:
                                  PredefinedExpr::IdentType IT);
   ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
   ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
+
+  bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
+
   ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
   ExprResult ActOnCharacterConstant(const Token &Tok,
                                     Scope *UDLScope = nullptr);

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Sun Oct 12 15:46:07 2014
@@ -601,8 +601,6 @@ void CodeGenFunction::EmitCondBrHints(ll
 
     LoopHintAttr::OptionType Option = LH->getOption();
     LoopHintAttr::LoopHintState State = LH->getState();
-    int ValueInt = LH->getValue();
-
     const char *MetadataName;
     switch (Option) {
     case LoopHintAttr::Vectorize:
@@ -622,6 +620,15 @@ void CodeGenFunction::EmitCondBrHints(ll
       MetadataName = "llvm.loop.unroll.count";
       break;
     }
+
+    Expr *ValueExpr = LH->getValue();
+    int ValueInt = 1;
+    if (ValueExpr) {
+      llvm::APSInt ValueAPS =
+          ValueExpr->EvaluateKnownConstInt(CGM.getContext());
+      ValueInt = static_cast<int>(ValueAPS.getSExtValue());
+    }
+
     llvm::Value *Value;
     llvm::MDString *Name;
     switch (Option) {

Modified: cfe/trunk/lib/Parse/ParsePragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParsePragma.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParsePragma.cpp (original)
+++ cfe/trunk/lib/Parse/ParsePragma.cpp Sun Oct 12 15:46:07 2014
@@ -724,16 +724,28 @@ bool Parser::HandlePragmaMSInitSeg(Strin
 struct PragmaLoopHintInfo {
   Token PragmaName;
   Token Option;
-  Token Value;
-  bool HasValue;
-  PragmaLoopHintInfo() : HasValue(false) {}
+  Token *Toks;
+  size_t TokSize;
+  PragmaLoopHintInfo() : Toks(nullptr), TokSize(0) {}
 };
 
+static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
+  std::string PragmaString;
+  if (PragmaName.getIdentifierInfo()->getName() == "loop") {
+    PragmaString = "clang loop ";
+    PragmaString += Option.getIdentifierInfo()->getName();
+  } else {
+    assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
+           "Unexpected pragma name");
+    PragmaString = "unroll";
+  }
+  return PragmaString;
+}
+
 bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
   assert(Tok.is(tok::annot_pragma_loop_hint));
   PragmaLoopHintInfo *Info =
       static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
-  ConsumeToken(); // The annotation token.
 
   IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
   Hint.PragmaNameLoc = IdentifierLoc::create(
@@ -747,50 +759,88 @@ bool Parser::HandlePragmaLoopHint(LoopHi
   Hint.OptionLoc = IdentifierLoc::create(
       Actions.Context, Info->Option.getLocation(), OptionInfo);
 
+  Token *Toks = Info->Toks;
+  size_t TokSize = Info->TokSize;
+
   // Return a valid hint if pragma unroll or nounroll were specified
   // without an argument.
   bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
   bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
-  if (!Info->HasValue && (PragmaUnroll || PragmaNoUnroll)) {
+  if (TokSize == 0 && (PragmaUnroll || PragmaNoUnroll)) {
+    ConsumeToken(); // The annotation token.
     Hint.Range = Info->PragmaName.getLocation();
     return true;
   }
 
-  // If no option is specified the argument is assumed to be numeric.
+  // The constant expression is always followed by an eof token, which increases
+  // the TokSize by 1.
+  assert(TokSize > 0 &&
+         "PragmaLoopHintInfo::Toks must contain at least one token.");
+
+  // If no option is specified the argument is assumed to be a constant expr.
   bool StateOption = false;
-  if (OptionInfo)
+  if (OptionInfo) { // Pragma unroll does not specify an option.
     StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
                       .Case("vectorize", true)
                       .Case("interleave", true)
                       .Case("unroll", true)
                       .Default(false);
+  }
+
+  // Verify loop hint has an argument.
+  if (Toks[0].is(tok::eof)) {
+    ConsumeToken(); // The annotation token.
+    Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument)
+        << /*StateArgument=*/StateOption << /*FullKeyword=*/PragmaUnroll;
+    return false;
+  }
 
   // Validate the argument.
   if (StateOption) {
+    ConsumeToken(); // The annotation token.
     bool OptionUnroll = OptionInfo->isStr("unroll");
-    SourceLocation StateLoc = Info->Value.getLocation();
-    IdentifierInfo *StateInfo = Info->Value.getIdentifierInfo();
+    SourceLocation StateLoc = Toks[0].getLocation();
+    IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
     if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full")
                                      : !StateInfo->isStr("enable")) &&
                        !StateInfo->isStr("disable"))) {
-      Diag(StateLoc, diag::err_pragma_invalid_keyword)
-          << /*MissingArgument=*/false << /*FullKeyword=*/OptionUnroll;
+      Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword)
+          << /*FullKeyword=*/OptionUnroll;
       return false;
     }
+    if (TokSize > 2)
+      Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+          << PragmaLoopHintString(Info->PragmaName, Info->Option);
     Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo);
   } else {
-    // FIXME: We should allow non-type template parameters for the loop hint
-    // value. See bug report #19610
-    if (Info->Value.is(tok::numeric_constant))
-      Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
-    else {
-      Diag(Info->Value.getLocation(), diag::err_pragma_loop_numeric_value);
-      return false;
+    // Enter constant expression including eof terminator into token stream.
+    PP.EnterTokenStream(Toks, TokSize, /*DisableMacroExpansion=*/false,
+                        /*OwnsTokens=*/false);
+    ConsumeToken(); // The annotation token.
+
+    ExprResult R = ParseConstantExpression();
+
+    // Tokens following an error in an ill-formed constant expression will
+    // remain in the token stream and must be removed.
+    if (Tok.isNot(tok::eof)) {
+      Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+          << PragmaLoopHintString(Info->PragmaName, Info->Option);
+      while (Tok.isNot(tok::eof))
+        ConsumeAnyToken();
     }
+
+    ConsumeToken(); // Consume the constant expression eof terminator.
+
+    if (R.isInvalid() ||
+        Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation()))
+      return false;
+
+    // Argument is a constant expression with an integer type.
+    Hint.ValueExpr = R.get();
   }
 
-  Hint.Range =
-      SourceRange(Info->PragmaName.getLocation(), Info->Value.getLocation());
+  Hint.Range = SourceRange(Info->PragmaName.getLocation(),
+                           Info->Toks[TokSize - 1].getLocation());
   return true;
 }
 
@@ -1796,31 +1846,21 @@ void PragmaOptimizeHandler::HandlePragma
 static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
                                Token Option, bool ValueInParens,
                                PragmaLoopHintInfo &Info) {
-  if (ValueInParens) {
-    if (Tok.is(tok::r_paren)) {
-      // Nothing between the parentheses.
-      std::string PragmaString;
-      if (PragmaName.getIdentifierInfo()->getName() == "loop") {
-        PragmaString = "clang loop ";
-        PragmaString += Option.getIdentifierInfo()->getName();
-      } else {
-        assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
-               "Unexpected pragma name");
-        PragmaString = "unroll";
-      }
-      // Don't try to emit what the pragma is expecting with the diagnostic
-      // because the logic is non-trivial and we give expected values in sema
-      // diagnostics if an invalid argument is given.  Here, just note that the
-      // pragma is missing an argument.
-      PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
-          << PragmaString << /*Expected=*/false;
-      return true;
+  SmallVector<Token, 1> ValueList;
+  int OpenParens = ValueInParens ? 1 : 0;
+  // Read constant expression.
+  while (Tok.isNot(tok::eod)) {
+    if (Tok.is(tok::l_paren))
+      OpenParens++;
+    else if (Tok.is(tok::r_paren)) {
+      OpenParens--;
+      if (OpenParens == 0 && ValueInParens)
+        break;
     }
-  }
 
-  // FIXME: Value should be stored and parsed as a constant expression.
-  Token Value = Tok;
-  PP.Lex(Tok);
+    ValueList.push_back(Tok);
+    PP.Lex(Tok);
+  }
 
   if (ValueInParens) {
     // Read ')'
@@ -1831,10 +1871,20 @@ static bool ParseLoopHintValue(Preproces
     PP.Lex(Tok);
   }
 
+  Token EOFTok;
+  EOFTok.startToken();
+  EOFTok.setKind(tok::eof);
+  EOFTok.setLocation(Tok.getLocation());
+  ValueList.push_back(EOFTok); // Terminates expression for parsing.
+
+  Token *TokenArray =
+      new (PP.getPreprocessorAllocator()) Token[ValueList.size()];
+  std::copy(ValueList.begin(), ValueList.end(), TokenArray);
+  Info.Toks = TokenArray;
+  Info.TokSize = ValueList.size();
+
   Info.PragmaName = PragmaName;
   Info.Option = Option;
-  Info.Value = Value;
-  Info.HasValue = true;
   return false;
 }
 
@@ -1975,7 +2025,6 @@ void PragmaUnrollHintHandler::HandlePrag
   if (Tok.is(tok::eod)) {
     // nounroll or unroll pragma without an argument.
     Info->PragmaName = PragmaName;
-    Info->HasValue = false;
     Info->Option.startToken();
   } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") {
     PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
@@ -1997,7 +2046,7 @@ void PragmaUnrollHintHandler::HandlePrag
     // In CUDA, the argument to '#pragma unroll' should not be contained in
     // parentheses.
     if (PP.getLangOpts().CUDA && ValueInParens)
-      PP.Diag(Info->Value.getLocation(),
+      PP.Diag(Info->Toks[0].getLocation(),
               diag::warn_pragma_unroll_cuda_value_in_parens);
 
     if (Tok.isNot(tok::eod)) {

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sun Oct 12 15:46:07 2014
@@ -3021,6 +3021,34 @@ static Expr *BuildFloatingLiteral(Sema &
   return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc);
 }
 
+bool Sema::CheckLoopHintExpr(Expr *E, SourceLocation Loc) {
+  assert(E && "Invalid expression");
+
+  if (E->isValueDependent())
+    return false;
+
+  QualType QT = E->getType();
+  if (!QT->isIntegerType() || QT->isBooleanType() || QT->isCharType()) {
+    Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_type) << QT;
+    return true;
+  }
+
+  llvm::APSInt ValueAPS;
+  ExprResult R = VerifyIntegerConstantExpression(E, &ValueAPS);
+
+  if (R.isInvalid())
+    return true;
+
+  bool ValueIsPositive = ValueAPS.isStrictlyPositive();
+  if (!ValueIsPositive || ValueAPS.getActiveBits() > 31) {
+    Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_value)
+        << ValueAPS.toString(10) << ValueIsPositive;
+    return true;
+  }
+
+  return false;
+}
+
 ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
   // Fast path for a single digit (which is quite common).  A single digit
   // cannot have a trigraph, escaped newline, radix prefix, or suffix.

Modified: cfe/trunk/lib/Sema/SemaStmtAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAttr.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmtAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmtAttr.cpp Sun Oct 12 15:46:07 2014
@@ -88,21 +88,15 @@ static Attr *handleLoopHintAttr(Sema &S,
     Spelling = LoopHintAttr::Pragma_clang_loop;
   }
 
-  int ValueInt = 1;
   LoopHintAttr::LoopHintState State = LoopHintAttr::Default;
   if (PragmaNoUnroll) {
     State = LoopHintAttr::Disable;
   } else if (Option == LoopHintAttr::VectorizeWidth ||
              Option == LoopHintAttr::InterleaveCount ||
              Option == LoopHintAttr::UnrollCount) {
-    // FIXME: We should support template parameters for the loop hint value.
-    // See bug report #19610.
-    llvm::APSInt ValueAPS;
-    if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) ||
-        (ValueInt = ValueAPS.getSExtValue()) < 1) {
-      S.Diag(A.getLoc(), diag::err_pragma_loop_invalid_value);
+    assert(ValueExpr && "Attribute must have a valid value expression.");
+    if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
       return nullptr;
-    }
   } else if (Option == LoopHintAttr::Vectorize ||
              Option == LoopHintAttr::Interleave ||
              Option == LoopHintAttr::Unroll) {
@@ -117,7 +111,7 @@ static Attr *handleLoopHintAttr(Sema &S,
   }
 
   return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
-                                      ValueInt, A.getRange());
+                                      ValueExpr, A.getRange());
 }
 
 static void

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Sun Oct 12 15:46:07 2014
@@ -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);
@@ -1127,6 +1129,24 @@ TemplateInstantiator::TransformTemplateP
   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,

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Sun Oct 12 15:46:07 2014
@@ -327,6 +327,27 @@ public:
   /// \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
@@ -5543,19 +5564,43 @@ TreeTransform<Derived>::TransformLabelSt
                                        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());
 }
 

Modified: cfe/trunk/test/CodeGen/pragma-loop.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/pragma-loop.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/pragma-loop.cpp (original)
+++ cfe/trunk/test/CodeGen/pragma-loop.cpp Sun Oct 12 15:46:07 2014
@@ -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;
@@ -74,28 +76,74 @@ void for_define_test(int *List, int Leng
   }
 }
 
+// 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
@@ -105,7 +153,8 @@ void template_test(double *List, int Len
   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:.*]]}
@@ -124,6 +173,19 @@ void template_test(double *List, int Len
 // 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}

Modified: cfe/trunk/test/Misc/ast-print-pragmas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/ast-print-pragmas.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/test/Misc/ast-print-pragmas.cpp (original)
+++ cfe/trunk/test/Misc/ast-print-pragmas.cpp Sun Oct 12 15:46:07 2014
@@ -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);
+}

Modified: cfe/trunk/test/PCH/pragma-loop.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/pragma-loop.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/test/PCH/pragma-loop.cpp (original)
+++ cfe/trunk/test/PCH/pragma-loop.cpp Sun Oct 12 15:46:07 2014
@@ -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
@@ -81,6 +83,15 @@ public:
       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
 
@@ -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

Modified: cfe/trunk/test/Parser/pragma-loop.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-loop.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/test/Parser/pragma-loop.cpp (original)
+++ cfe/trunk/test/Parser/pragma-loop.cpp Sun Oct 12 15:46:07 2014
@@ -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;
 
@@ -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
@@ -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
-
-/* 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)
+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 {{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;
   }
@@ -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;
   }

Modified: cfe/trunk/test/Parser/pragma-unroll.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-unroll.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/test/Parser/pragma-unroll.cpp (original)
+++ cfe/trunk/test/Parser/pragma-unroll.cpp Sun Oct 12 15:46:07 2014
@@ -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;
@@ -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;
   }

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=219589&r1=219588&r2=219589&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Sun Oct 12 15:46:07 2014
@@ -1669,8 +1669,16 @@ static void EmitAttrList(raw_ostream &OS
   }
 }
 
-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);
@@ -1696,14 +1704,25 @@ void EmitClangAttrList(RecordKeeper &Rec
         " 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))
@@ -1712,6 +1731,7 @@ void EmitClangAttrList(RecordKeeper &Rec
       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);
@@ -1720,6 +1740,8 @@ void EmitClangAttrList(RecordKeeper &Rec
   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";
 }
 





More information about the cfe-commits mailing list