Fair, but we don't need that tested multiple times.
I want to be sure that all these pragmas are handled correctly in different 
situations, like free functions, member functions, templates.

That means -ast-print is broken and should be fixed.
Ok, will fix it.

Can we update the name of the function to suggest this?
Ok, will do.

Best regards,
Alexey Bataev
=============
Software Engineer
Intel Compiler Team

07.07.2015 15:18, Aaron Ballman пишет:
On Tue, Jul 7, 2015 at 7:40 AM, Bataev, Alexey <a.bat...@hotmail.com> wrote:
I tend to agree with hal that this should be a warning. It's low
priority, definitely, but silently allowing the programmer to get away
with incorrect code doesn't seem beneficial to anyone. It would also
point out the two other places in your tests that have this exact same
code pattern with no additional testing benefit. ;-)

This code is correct, OpenMP standard allows to mark the same function many
times with the same pragma. Here is an excerpt:
Eww, but fair enough. :-)

#pragma omp declare simd [clause[[,] clause] ...] new-line
[#pragma omp declare simd [clause[[,] clause] ...] new-line]
[...]
function definition or declaration

There may be multiple declare simd directives for a function (C, C++,
Fortran) or subroutine (Fortran).

I would also like to see a test for #pragma omp declare simd that is
at the end of the TU with no futher statements (to ensure it gets
diagnosed).

Ok, will be added.

Copy paste error?
Nope, I have to verify that the compiler allows to mark the same function
several times with '#pragma omp declare simd' according to standard.
Fair, but we don't need that tested multiple times.

This attribute has a pragma spelling where the namespace is openmp and
the name is declare. It's the same pattern used by the loop hint and
init_seg pragmas.

Can't add spellings, it breaks -ast-print mode (pragmas are printed just
like attributes, directly after function declaration).
That means -ast-print is broken and should be fixed.

Please document this attribute as it does have a pragma spelling.

Will add

This attribute appears to be missing its Subjects clause as well.
That's not information we currently care about for pragmas, but I
would like the declarative part of the attribute to match the semantic
expectations.

Will add too.

I've not seen any tests for ObjC, so does this really apply to methods?
I'll fix this message.

Capitalize the first word in the documentation part of the sentence.
Thanks, fixed.

Drop the virtual, add override.
Fixed.

Drop the "if"
Fixed

Can you use a range-based for loop please?
Done

This is not an implicit attribute because it's the direct result of
the user typing something in source code.
Fixed.

This really weirds me out. That means this function doesn't parse just
the pragma, it also parses any external declaration.
Yes, we have to parse function right after pragma to be able correctly
handle clauses associated with this pragma. These clauses may have refernces
to function arguments and because of that we have to parse the function
first and only then the pragma itself.
Can we update the name of the function to suggest this?

The comments don't look correct here.
Missed this one, thanks.

Is this safe to assert in a parsing method, or should this be diagnosed?
There always must be at least one token if the compiler works correctly -
tok::annot_pragma_openmp. No need to diagnose.
Good deal, thank you!

Has this situation already been diagnosed? If so, then why are we
generating the tokens in a way that require this work? And if not, are
we missing a diagnostic here?
Yes, this was diagnosed already. We need to remove cached tokens, so just
skip them.
Thank you!

~Aaron

Attribute is not implicit.
Fixed.

Best regards,
Alexey Bataev
=============
Software Engineer
Intel Compiler Team

06.07.2015 16:13, Aaron Ballman пишет:

On Mon, Jun 22, 2015 at 7:35 AM, Alexey Bataev <a.bat...@hotmail.com>
wrote:
Hi rsmith, aaron.ballman, hfinkel, ejstotzer, fraggamuffin,

Inital parsing/sema/serialization/deserialization support for '#pragma
omp declare simd' directive.
The declare simd construct can be applied to a function to enable the
creation of one or more versions that can process multiple arguments using
SIMD instructions from a single invocation from a SIMD loop.
If the function has any declarations, then the declare simd construct for
any declaration that has one must be equivalent to the one specified for the
definition. Otherwise, the result is unspecified.
This pragma can be aplied many times to the same declaration.
Internally this pragma is represented as an attribute. But we need
special processing for this pragma because it must be used before function
declaration, this directive is appplied to.
If pragma is applied to method declared/defined in the class lexical
context, then the delayed parsing procedure is used.
Also delayed parsing is used for poarsing a pragma itself, because this
directive has several clauses that can reference arguments of the associated
function/method.

http://reviews.llvm.org/D10599

Files:
    include/clang/AST/ASTMutationListener.h
    include/clang/Basic/Attr.td
    include/clang/Basic/DiagnosticParseKinds.td
    include/clang/Basic/DiagnosticSemaKinds.td
    include/clang/Basic/OpenMPKinds.def
    include/clang/Parse/Parser.h
    include/clang/Sema/Sema.h
    include/clang/Serialization/ASTWriter.h
    lib/AST/DeclPrinter.cpp
    lib/Basic/OpenMPKinds.cpp
    lib/Frontend/MultiplexConsumer.cpp
    lib/Parse/ParseDeclCXX.cpp
    lib/Parse/ParseOpenMP.cpp
    lib/Parse/Parser.cpp
    lib/Sema/SemaOpenMP.cpp
    lib/Serialization/ASTCommon.h
    lib/Serialization/ASTReaderDecl.cpp
    lib/Serialization/ASTWriter.cpp
    test/OpenMP/declare_simd_ast_print.c
    test/OpenMP/declare_simd_ast_print.cpp
    test/OpenMP/declare_simd_messages.cpp

EMAIL PREFERENCES
    http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/OpenMP/declare_simd_messages.cpp
===================================================================
--- test/OpenMP/declare_simd_messages.cpp
+++ test/OpenMP/declare_simd_messages.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp
-x c++ -std=c++11 %s
+
+// expected-error@+1 {{expected an OpenMP directive}}
+#pragma omp declare
+
+// expected-error@+2 {{'#pragma omp declare simd' can be applied to
functions or methods only}}
+#pragma omp declare simd
+int a;
+// expected-error@+2 {{'#pragma omp declare simd' can be applied to
functions or methods only}}
+#pragma omp declare simd
+#pragma omp threadprivate(a)
+int var;
+#pragma omp threadprivate(var)
+
+// expected-error@+2 {{expected an OpenMP directive}}
+#pragma omp declare simd
+#pragma omp declare
+
+#pragma omp declare simd
+#pragma omp declare simd

I tend to agree with hal that this should be a warning. It's low
priority, definitely, but silently allowing the programmer to get away
with incorrect code doesn't seem beneficial to anyone. It would also
point out the two other places in your tests that have this exact same
code pattern with no additional testing benefit. ;-)

+int main();
+
+#pragma omp declare simd
+template <class C>
+void h(C *hp, C *hp2, C *hq, C *lin) {
+}
+
+#pragma omp declare simd
+template <>
+void h(int *hp, int *hp2, int *hq, int *lin) {
+  h((float *)hp, (float *)hp2, (float *)hq, (float *)lin);
+}
+
+template <class T>
+struct St {
+#pragma omp declare simd
+  void h(T *hp) {
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp declare
simd'}}
+#pragma omp declare simd
+    *hp = *t;
+  }
+
+private:
+  T t;
+};

I would also like to see a test for #pragma omp declare simd that is
at the end of the TU with no futher statements (to ensure it gets
diagnosed).

Index: test/OpenMP/declare_simd_ast_print.cpp
===================================================================
--- test/OpenMP/declare_simd_ast_print.cpp
+++ test/OpenMP/declare_simd_ast_print.cpp
@@ -0,0 +1,103 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -ast-print %s |
FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -include-pch %t
-fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare simd
+void add_1(float *d);
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: void add_1(float *d);
+//
+
+#pragma omp declare simd
+template <class C> void h(C *hp, C *hp2, C *hq, C *lin) {
+}
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: template <class C = int> void h(int *hp, int *hp2, int
*hq, int *lin) {
+// CHECK-NEXT: h((float *)hp, (float *)hp2, (float *)hq, (float *)lin);
+// CHECK-NEXT: }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: template <class C = float> void h(float *hp, float
*hp2, float *hq, float *lin) {
+// CHECK-NEXT: }
+
+// CHECK: #pragma omp declare simd
+// CHECK: template <class C> void h(C *hp, C *hp2, C *hq, C *lin) {
+// CHECK-NEXT: }
+//
+
+// Instatiate with <C=int> explicitly.
+// Pragmas need to be same, otherwise standard says that's undefined
behavior.
+#pragma omp declare simd
+template <>
+void h(int *hp, int *hp2, int *hq, int *lin)
+{
+  // Instatiate with <C=float> implicitly.
+  // This is special case where the directive is stored by Sema and is
+  // generated together with the (pending) function instatiation.
+  h((float*) hp, (float*) hp2, (float*) hq, (float*) lin);
+}
+
+class VV {
+  // CHECK: #pragma omp declare simd
+  // CHECK-NEXT: int add(int a, int b)     {
+  // CHECK-NEXT: return a + b;
+  // CHECK-NEXT: }
+  #pragma omp declare simd
+  int add(int a, int b) { return a + b; }
+
+  // CHECK: #pragma omp declare simd
+  // CHECK-NEXT: #pragma omp declare simd
+  // CHECK-NEXT: float addpf(float *a, float *b)     {
+  // CHECK-NEXT: return *a + *b;
+  // CHECK-NEXT: }
+  #pragma omp declare simd
+  #pragma omp declare simd

Copy paste error?

+  float addpf(float *a, float *b) { return *a + *b; }
+};
+
+// CHECK: template <int X = 16> class TVV {
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int a, int b);
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: float taddpf(float *a, float *b) {
+// CHECK-NEXT: return *a + *b;
+// CHECK-NEXT: }
+// CHECK: }
+template <int X>
+class TVV {
+public:
+// CHECK: template <int X> class TVV {
+  #pragma omp declare simd
+  int tadd(int a, int b) { return a + b; }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int a, int b) {
+// CHECK-NEXT: return a + b;
+// CHECK-NEXT: }
+
+
+  #pragma omp declare simd
+  float taddpf(float *a, float *b) { return *a + *b; }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: float taddpf(float *a, float *b) {
+// CHECK-NEXT: return *a + *b;
+// CHECK-NEXT: }
+};
+// CHECK: };
+
+// CHECK: TVV<16> t16;
+TVV<16> t16;
+
+void f() {
+  float a = 1.0f, b = 2.0f;
+  float r = t16.taddpf(&a, &b);
+}
+
+#endif
Index: test/OpenMP/declare_simd_ast_print.c
===================================================================
--- test/OpenMP/declare_simd_ast_print.c
+++ test/OpenMP/declare_simd_ast_print.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -include-pch %t -fsyntax-only -verify %s
-ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare simd
+#pragma omp declare simd

Copy paste error?

+void add_1(float *d, float *s1, float *s2);
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: void add_1(float *d, float *s1, float *s2)
+
+#endif
Index: include/clang/Basic/OpenMPKinds.def
===================================================================
--- include/clang/Basic/OpenMPKinds.def
+++ include/clang/Basic/OpenMPKinds.def
@@ -94,6 +94,7 @@
   OPENMP_DIRECTIVE_EXT(parallel_for_simd, "parallel for simd")
   OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections")
   OPENMP_DIRECTIVE_EXT(for_simd, "for simd")
+OPENMP_DIRECTIVE_EXT(declare_simd, "declare simd")

   // OpenMP clauses.
   OPENMP_CLAUSE(if, OMPIfClause)
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -2044,3 +2044,19 @@
     let SemaHandler = 0;
     let Documentation = [Undocumented];
   }
+
+def OMPDeclareSimdDecl : InheritableAttr {
+  // This attribute has no spellings as it is only ever created
implicitly.
+  let Spellings = [];

This attribute has a pragma spelling where the namespace is openmp and
the name is declare. It's the same pattern used by the loop hint and
init_seg pragmas.

+  let SemaHandler = 0;
+  let Documentation = [Undocumented];

Please document this attribute as it does have a pragma spelling.

+  let Args = [UnsignedArgument<"NumberOfDirectives">,
BoolArgument<"Complete">];
+  let AdditionalMembers = [{
+  void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy)
const {
+    OS << "#pragma omp declare simd\n";
+  }
+  void setNumberOfDirectives(unsigned N) { numberOfDirectives = N; }
+  void setComplete() { complete = true; }

This attribute appears to be missing its Subjects clause as well.
That's not information we currently care about for pragmas, but I
would like the declarative part of the attribute to match the semantic
expectations.

+  }];
+}
+
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -989,6 +989,8 @@
     "'#pragma omp %0' cannot be an immediate substatement">;
   def err_omp_expected_identifier_for_critical : Error<
     "expected identifier specifying the name of the 'omp critical'
directive">;
+def err_omp_single_decl_in_declare_simd : Error<
+  "single declaration is expected with 'declare simd' directive">;

   // Pragma loop support.
   def err_pragma_loop_missing_argument : Error<
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7601,6 +7601,8 @@
     "the 'copyprivate' clause must not be used with the 'nowait' clause">;
   def note_omp_nowait_clause_here : Note<
     "'nowait' clause is here">;
+def err_omp_function_expected : Error<
+  "'#pragma omp declare simd' can be applied to functions or methods
only">;

I've not seen any tests for ObjC, so does this really apply to methods?

   } // end of OpenMP category

   let CategoryName = "Related Result Type Issue" in {
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -144,6 +144,7 @@
     class ObjCPropertyDecl;
     class ObjCProtocolDecl;
     class OMPThreadPrivateDecl;
+  class OMPDeclareSimdDecl;
     class OMPClause;
     class OverloadCandidateSet;
     class OverloadExpr;
@@ -7758,6 +7759,13 @@
                                          Stmt *AStmt, SourceLocation
StartLoc,
                                          SourceLocation EndLoc);

+  /// \brief Called on well-formed '\#pragma omp declare simd' after
parsing of
+  /// the associated method/function.
+  DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(ArrayRef<OMPClause *>
Clauses,
+                                                 Decl *ADecl,
+                                                 SourceLocation StartLoc,
+                                                 bool LastDirective);
+
     OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
                                            Expr *Expr,
                                            SourceLocation StartLoc,
Index: include/clang/AST/ASTMutationListener.h
===================================================================
--- include/clang/AST/ASTMutationListener.h
+++ include/clang/AST/ASTMutationListener.h
@@ -113,6 +113,12 @@
     /// \param D the declaration marked OpenMP threadprivate.
     virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {}

+  /// \brief A declaration is marked as OpenMP declare simd which was not
+  /// previously marked as declare simd.
+  ///
+  /// \param D the declaration marked OpenMP declare simd.

Capitalize the first word in the documentation part of the sentence.

+  virtual void DeclarationMarkedOpenMPDeclareSimd(const Decl *D) {}
+
     /// \brief A definition has been made visible by being redefined
locally.
     ///
     /// \param D The definition that was previously not visible.
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1019,6 +1019,19 @@
       CachedTokens *ExceptionSpecTokens;
     };

+  /// \brief An OpenMP declaration inside a class.
+  struct LateParsedOpenMPDeclaration : public LateParsedDeclaration {
+    explicit LateParsedOpenMPDeclaration(Parser *P) : Self(P) {}
+
+    virtual void ParseLexedMethodDeclarations();

Drop the virtual, add override.

+
+    Parser *Self;
+
+    /// \brief The set of tokens that make up an exception-specification
that
+    /// has not yet been parsed.
+    CachedTokens Tokens;
+  };
+
     /// LateParsedMemberInitializer - An initializer for a non-static
class data
     /// member whose parsing must to be delayed until the class is
completely
     /// defined (C++11 [class.mem]p2).
@@ -2364,7 +2377,13 @@

//===--------------------------------------------------------------------===//
     // OpenMP: Directives and clauses.
     /// \brief Parses declarative OpenMP directives.
-  DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+  /// \param Level Current level of declarative directive, in case if it
is

Drop the "if"

+  /// allowed to apply multiple declarative directives to the same
declaration.
+  DeclGroupPtrTy ParseOpenMPDeclarativeDirective(bool IsInTagDecl,
+                                                 unsigned Level = 0);
+  /// \brief Late parse directive.
+  void LateParseOpenMPDeclarativeDirective(OpenMPDirectiveKind DKind,
+                                           SourceLocation Loc);
     /// \brief Parses simple list of variables.
     ///
     /// \param Kind Kind of the directive.
Index: include/clang/Serialization/ASTWriter.h
===================================================================
--- include/clang/Serialization/ASTWriter.h
+++ include/clang/Serialization/ASTWriter.h
@@ -859,6 +859,7 @@
                                       const ObjCCategoryDecl *ClassExt)
override;
     void DeclarationMarkedUsed(const Decl *D) override;
     void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+  void DeclarationMarkedOpenMPDeclareSimd(const Decl *D) override;
     void RedefinedHiddenDefinition(const NamedDecl *D, Module *M)
override;
   };

Index: lib/Frontend/MultiplexConsumer.cpp
===================================================================
--- lib/Frontend/MultiplexConsumer.cpp
+++ lib/Frontend/MultiplexConsumer.cpp
@@ -127,6 +127,7 @@
                                       const ObjCCategoryDecl *ClassExt)
override;
     void DeclarationMarkedUsed(const Decl *D) override;
     void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+  void DeclarationMarkedOpenMPDeclareSimd(const Decl *D) override;
     void RedefinedHiddenDefinition(const NamedDecl *D, Module *M)
override;

   private:
@@ -221,6 +222,11 @@
     for (size_t i = 0, e = Listeners.size(); i != e; ++i)
       Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
   }
+void MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareSimd(
+    const Decl *D) {
+  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+    Listeners[i]->DeclarationMarkedOpenMPDeclareSimd(D);
+}

Can you use a range-based for loop please?

   void MultiplexASTMutationListener::RedefinedHiddenDefinition(const
NamedDecl *D,
                                                                Module *M)
{
     for (auto *L : Listeners)
Index: lib/Basic/OpenMPKinds.cpp
===================================================================
--- lib/Basic/OpenMPKinds.cpp
+++ lib/Basic/OpenMPKinds.cpp
@@ -324,6 +324,8 @@
         break;
       }
       break;
+  case OMPD_declare_simd:
+    break;
     case OMPD_unknown:
     case OMPD_threadprivate:
     case OMPD_section:
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -1283,6 +1283,7 @@
     case OMPD_barrier:
     case OMPD_taskwait:
     case OMPD_flush:
+  case OMPD_declare_simd:
       llvm_unreachable("OpenMP Directive is not allowed");
     case OMPD_unknown:
       llvm_unreachable("Unknown OpenMP directive");
@@ -1989,6 +1990,7 @@
                                        EndLoc);
       break;
     case OMPD_threadprivate:
+  case OMPD_declare_simd:
       llvm_unreachable("OpenMP Directive is not allowed");
     case OMPD_unknown:
       llvm_unreachable("Unknown OpenMP directive");
@@ -2006,6 +2008,34 @@
     return Res;
   }

+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareSimdDirective(ArrayRef<OMPClause *> Clauses,
+                                      Decl *ADecl, SourceLocation
StartLoc,
+                                      bool LastDirective) {
+  if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl)) {
+    ADecl = FTD->getTemplatedDecl();
+  }

Elide braces.

+  if (!isa<FunctionDecl>(ADecl)) {
+    Diag(ADecl->getLocation(), diag::err_omp_function_expected)
+        << ADecl->getDeclContext()->isFileContext();
+    return DeclGroupPtrTy();
+  }
+  if (auto *Attr = ADecl->getAttr<OMPDeclareSimdDeclAttr>()) {
+    if (!Attr->getComplete()) {
+      Attr->setNumberOfDirectives(Attr->getNumberOfDirectives() + 1);
+      if (LastDirective)
+        Attr->setComplete();
+    }
+  } else {
+    auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(
+        Context, 1, LastDirective, SourceRange(StartLoc, StartLoc));

This is not an implicit attribute because it's the direct result of
the user typing something in source code.

+    ADecl->addAttr(NewAttr);
+    if (auto *ML = Context.getASTMutationListener())
+      ML->DeclarationMarkedOpenMPDeclareSimd(ADecl);
+  }
+  return ConvertDeclToDeclGroup(ADecl);
+}
+
   StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *>
Clauses,
                                                 Stmt *AStmt,
                                                 SourceLocation StartLoc,
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -36,6 +36,7 @@
       void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls);

       void Print(AccessSpecifier AS);
+    void print(OMPDeclareSimdDeclAttr *A);

       /// Print an Objective-C method type in parentheses.
       ///
@@ -405,7 +406,22 @@
     }
   }

+void DeclPrinter::print(OMPDeclareSimdDeclAttr *A) {
+  for (unsigned i = 0; i < A->getNumberOfDirectives(); ++i) {
+    A->printPrettyPragma(Out, Policy);
+    Indent();
+  }
+}
+
   void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+  if (auto *Attr = D->getAttr<OMPDeclareSimdDeclAttr>()) {
+    if (D->getTemplatedKind() !=
+            FunctionDecl::TK_FunctionTemplateSpecialization &&
+        D->getTemplatedKind() != FunctionDecl::TK_FunctionTemplate &&
+        D->getTemplatedKind() !=
+            FunctionDecl::TK_DependentFunctionTemplateSpecialization)
+      print(Attr);
+  }
     CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
     CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
     if (!Policy.SuppressSpecifiers) {
@@ -912,11 +928,17 @@
     if (PrintInstantiation) {
       TemplateParameterList *Params = D->getTemplateParameters();
       for (auto *I : D->specializations()) {
+      if (auto *Attr = I->getAttr<OMPDeclareSimdDeclAttr>()) {
+        print(Attr);
+      }

Elide braces.

         PrintTemplateParameters(Params,
I->getTemplateSpecializationArgs());
         Visit(I);
       }
     }

+  if (auto *Attr =
D->getTemplatedDecl()->getAttr<OMPDeclareSimdDeclAttr>()) {
+    print(Attr);
+  }

Elide braces.

     return VisitRedeclarableTemplateDecl(D);
   }

Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -2942,7 +2942,7 @@
         }

         if (Tok.is(tok::annot_pragma_openmp)) {
-        ParseOpenMPDeclarativeDirective();
+        ParseOpenMPDeclarativeDirective(/*IsInTagDecl=*/true);
           continue;
         }

Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -30,18 +30,26 @@
     // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
     // TODO: add other combined directives in topological order.
     const OpenMPDirectiveKind F[][3] = {
-    { OMPD_for, OMPD_simd, OMPD_for_simd },
-    { OMPD_parallel, OMPD_for, OMPD_parallel_for },
-    { OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd },
-    { OMPD_parallel, OMPD_sections, OMPD_parallel_sections }
+      {OMPD_unknown /*declare*/, OMPD_simd, OMPD_declare_simd},
+      {OMPD_for, OMPD_simd, OMPD_for_simd},
+      {OMPD_parallel, OMPD_for, OMPD_parallel_for},
+      {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd},
+      {OMPD_parallel, OMPD_sections, OMPD_parallel_sections}
     };
     auto Tok = P.getCurToken();
     auto DKind =
         Tok.isAnnotation()
             ? OMPD_unknown
             :
getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
+  bool TokenMatched = false;
     for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) {
-    if (DKind == F[i][0]) {
+    if (!Tok.isAnnotation() && DKind == OMPD_unknown) {
+      TokenMatched =
+          (i == 0) &&
!P.getPreprocessor().getSpelling(Tok).compare("declare");
+    } else {
+      TokenMatched = DKind == F[i][0];
+    }

Elide braces.

+    if (TokenMatched) {
         Tok = P.getPreprocessor().LookAhead(0);
         auto SDKind =
             Tok.isAnnotation()
@@ -61,13 +69,17 @@
   ///       threadprivate-directive:
   ///         annot_pragma_openmp 'threadprivate' simple-variable-list
   ///
-Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
+Parser::DeclGroupPtrTy
+Parser::ParseOpenMPDeclarativeDirective(bool IsInTagDecl, unsigned Level)
{
     assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP
directive!");
     ParenBraceBracketBalancer BalancerRAIIObj(*this);

+  auto AnnotationVal =
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
     SourceLocation Loc = ConsumeToken();
     SmallVector<Expr *, 5> Identifiers;
-  auto DKind = ParseOpenMPDirectiveKind(*this);
+  OpenMPDirectiveKind DKind =
+      (AnnotationVal == 0) ? ParseOpenMPDirectiveKind(*this)
+                           :
static_cast<OpenMPDirectiveKind>(AnnotationVal);

     switch (DKind) {
     case OMPD_threadprivate:
@@ -85,6 +97,86 @@
         return Actions.ActOnOpenMPThreadprivateDirective(Loc,
Identifiers);
       }
       break;
+  case OMPD_declare_simd: {
+    // The syntax is:
+    // { #pragma omp declare simd }
+    // <function-declaration-or-definition>
+    //
+    if (AnnotationVal == 0) {
+      // Skip 'simd' if it was restored from cached tokens.
+      ConsumeToken();
+    }

Elide braces.

+    if (IsInTagDecl) {
+      LateParseOpenMPDeclarativeDirective(/*DKind=*/OMPD_declare_simd,
Loc);
+      return DeclGroupPtrTy();
+    }
+
+    SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown
+ 1>
+        FirstClauses(OMPC_unknown + 1);
+    SmallVector<OMPClause *, 4> Clauses;
+    SmallVector<Token, 8> CachedPragmas;
+
+    while (Tok.isNot(tok::annot_pragma_openmp_end) &&
Tok.isNot(tok::eof)) {
+      CachedPragmas.push_back(Tok);
+      ConsumeAnyToken();
+    }
+    CachedPragmas.push_back(Tok);
+    if (Tok.isNot(tok::eof))
+      ConsumeAnyToken();
+
+    DeclGroupPtrTy Ptr;
+    if (Tok.is(tok::annot_pragma_openmp)) {
+      Ptr = ParseOpenMPDeclarativeDirective(IsInTagDecl, Level + 1);
+    } else {
+      // Here we expect to see some function declaration.
+      ParsedAttributesWithRange attrs(AttrFactory);
+      MaybeParseCXX11Attributes(attrs);
+      MaybeParseMicrosoftAttributes(attrs);
+      ParsingDeclSpec PDS(*this);
+      Ptr = ParseExternalDeclaration(attrs, &PDS);

This really weirds me out. That means this function doesn't parse just
the pragma, it also parses any external declaration.

+    }
+    if (!Ptr || Ptr.get().isNull())
+      return DeclGroupPtrTy();
+    if (Ptr.get().isDeclGroup()) {
+      Diag(Tok, diag::err_omp_single_decl_in_declare_simd);
+      return DeclGroupPtrTy();
+    }
+
+    // Append the current token at the end of the new token stream so
that it
+    // doesn't get lost.
+    CachedPragmas.push_back(Tok);
+    // Push back tokens for pragma.
+    PP.EnterTokenStream(CachedPragmas.data(), CachedPragmas.size(),
+                        /*DisableMacroExpansion=*/true,
+                        /*OwnsTokens=*/false);
+    // Parse pragma itself.
+    // Consume the previously pushed token.
+    ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+    Actions.StartOpenMPClauses();
+    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+      OpenMPClauseKind CKind = Tok.isAnnotation()
+                                   ? OMPC_unknown
+                                   :
getOpenMPClauseKind(PP.getSpelling(Tok));
+      OMPClause *Clause =
+          ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
+      FirstClauses[CKind].setInt(true);
+      if (Clause) {
+        FirstClauses[CKind].setPointer(Clause);
+        Clauses.push_back(Clause);
+      }
+
+      // Skip ',' if any.
+      if (Tok.is(tok::comma))
+        ConsumeToken();
+    }
+    Actions.EndOpenMPClauses();
+    // Consume final annot_pragma_openmp_end.
+    ConsumeToken();
+
+    return Actions.ActOnOpenMPDeclareSimdDirective(
+        Clauses, Ptr.get().getSingleDecl(), Loc, Level == 0);
+  }
     case OMPD_unknown:
       Diag(Tok, diag::err_omp_unknown_directive);
       break;
@@ -118,6 +210,69 @@
     return DeclGroupPtrTy();
   }

+/// \brief Late parsing of declarative OpenMP directives.
+///
+///       threadprivate-directive:
+///         annot_pragma_openmp 'threadprivate' simple-variable-list

The comments don't look correct here.

+///         annot_pragma_openmp_end
+///
+void Parser::LateParseOpenMPDeclarativeDirective(OpenMPDirectiveKind
DKind,
+                                                 SourceLocation Loc) {
+  if (DKind == OMPD_declare_simd) {
+    LateParsedOpenMPDeclaration *Decl = new
LateParsedOpenMPDeclaration(this);
+    getCurrentClass().LateParsedDeclarations.push_back(Decl);
+
+    Token LocalTok;
+    LocalTok.startToken();
+    LocalTok.setKind(tok::annot_pragma_openmp);
+    LocalTok.setLocation(Loc);
+    LocalTok.setAnnotationValue(
+        reinterpret_cast<void
*>(static_cast<uintptr_t>(OMPD_declare_simd)));
+    Decl->Tokens.push_back(LocalTok);
+
+    do {
+      while (Tok.isNot(tok::annot_pragma_openmp_end) &&
Tok.isNot(tok::eof)) {
+        Decl->Tokens.push_back(Tok);
+        ConsumeAnyToken();
+      }
+      Decl->Tokens.push_back(Tok);
+      if (Tok.isNot(tok::eof))
+        ConsumeAnyToken();
+    } while (Tok.is(tok::annot_pragma_openmp));
+
+    LexTemplateFunctionForLateParsing(Decl->Tokens);
+  }
+}
+
+/// \brief Actual parsing of late OpenMP declaration.
+void Parser::LateParsedOpenMPDeclaration::ParseLexedMethodDeclarations()
{
+  // Save the current token position.
+  SourceLocation OrigLoc = Self->Tok.getLocation();
+
+  assert(!Tokens.empty() && "Empty body!");

Is this safe to assert in a parsing method, or should this be diagnosed?

+  // Append the current token at the end of the new token stream so that
it
+  // doesn't get lost.
+  Tokens.push_back(Self->Tok);
+  Self->PP.EnterTokenStream(Tokens.data(), Tokens.size(), true, false);
+
+  // Consume the previously pushed token.
+  Self->ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+  Self->ParseOpenMPDeclarativeDirective(/*IsInTagDecl=*/false);
+
+  if (Self->Tok.getLocation() != OrigLoc) {
+    // Due to parsing error, we either went over the cached tokens or
+    // there are still cached tokens left. If it's the latter case skip
the
+    // leftover tokens.
+    // Since this is an uncommon situation that should be avoided, use
the
+    // expensive isBeforeInTranslationUnit call.
+    if (Self->PP.getSourceManager().isBeforeInTranslationUnit(
+            Self->Tok.getLocation(), OrigLoc))
+      while (Self->Tok.getLocation() != OrigLoc &&
Self->Tok.isNot(tok::eof))
+        Self->ConsumeAnyToken();

Has this situation already been diagnosed? If so, then why are we
generating the tokens in a way that require this work? And if not, are
we missing a diagnostic here?

+  }
+}
+
   /// \brief Parsing of declarative or executable OpenMP directives.
   ///
   ///       threadprivate-directive:
@@ -274,6 +429,11 @@
       OMPDirectiveScope.Exit();
       break;
     }
+  case OMPD_declare_simd:
+    Diag(Tok, diag::err_omp_unexpected_directive)
+        << getOpenMPDirectiveName(DKind);
+    SkipUntil(tok::annot_pragma_openmp_end);
+    break;
     case OMPD_unknown:
       Diag(Tok, diag::err_omp_unknown_directive);
       SkipUntil(tok::annot_pragma_openmp_end);
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -653,7 +653,7 @@
       HandlePragmaOpenCLExtension();
       return DeclGroupPtrTy();
     case tok::annot_pragma_openmp:
-    return ParseOpenMPDeclarativeDirective();
+    return ParseOpenMPDeclarativeDirective(/*IsInTagDecl=*/false);
     case tok::annot_pragma_ms_pointers_to_members:
       HandlePragmaMSPointersToMembers();
       return DeclGroupPtrTy();
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -3888,6 +3888,14 @@
             Reader.Context, ReadSourceRange(Record, Idx)));
         break;

+    case UPD_DECL_MARKED_OPENMP_DECLARE_SIMD: {
+      auto *Attr = OMPDeclareSimdDeclAttr::CreateImplicit(
+          Reader.Context, Record[Idx++], Record[Idx++] != 0,
+          ReadSourceRange(Record, Idx));

Attribute is not implicit.

+      D->addAttr(Attr);
+      break;
+    }
+
       case UPD_DECL_EXPORTED:
         unsigned SubmoduleID = readSubmoduleID(Record, Idx);
         auto *Exported = cast<NamedDecl>(D);
Index: lib/Serialization/ASTCommon.h
===================================================================
--- lib/Serialization/ASTCommon.h
+++ lib/Serialization/ASTCommon.h
@@ -36,6 +36,7 @@
     UPD_MANGLING_NUMBER,
     UPD_STATIC_LOCAL_NUMBER,
     UPD_DECL_MARKED_OPENMP_THREADPRIVATE,
+  UPD_DECL_MARKED_OPENMP_DECLARE_SIMD,
     UPD_DECL_EXPORTED
   };

Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -4615,6 +4615,14 @@
                          Record);
           break;

+      case UPD_DECL_MARKED_OPENMP_DECLARE_SIMD: {
+        auto *Attr = D->getAttr<OMPDeclareSimdDeclAttr>();
+        AddSourceRange(Attr->getRange(), Record);
+        Record.push_back(Attr->getNumberOfDirectives());
+        Record.push_back(Attr->getComplete() ? 1 : 0);
+        break;
+      }
+
         case UPD_DECL_EXPORTED:
           Record.push_back(getSubmoduleID(Update.getModule()));
           break;
@@ -5761,6 +5769,14 @@

DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
   }

+void ASTWriter::DeclarationMarkedOpenMPDeclareSimd(const Decl *D) {
+  assert(!WritingAST && "Already writing the AST!");
+  if (!D->isFromASTFile())
+    return;
+
+
DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_DECLARE_SIMD));
+}
+
   void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M)
{
     assert(!WritingAST && "Already writing the AST!");
     assert(D->isHidden() && "expected a hidden declaration");



_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to