[PATCH] [OPENMP] Initial support for '#pragma omp declare simd' directive.

Bataev, Alexey a.bataev at hotmail.com
Tue Jul 7 05:52:02 PDT 2015


Hal, it is not a problem to emit the diagnostic for naked pragmas, but I 
expect a lot of troubles with warnings for pragmas with a lot of 
clauses, mixed different way. But if you really-really think, that we 
need this stuff, I'll add it. :)

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

07.07.2015 15:35, Hal Finkel пишет:
> ----- Original Message -----
>> From: "Aaron Ballman" <aaron.ballman at gmail.com>
>> To: "Alexey Bataev" <a.bataev at hotmail.com>
>> Cc: reviews+D10599+public+2871690e17faf647 at reviews.llvm.org, "Richard Smith" <richard at metafoo.co.uk>, "Hal Finkel"
>> <hfinkel at anl.gov>, ejstotzer at gmail.com, fraggamuffin at gmail.com, "llvm cfe" <cfe-commits at cs.uiuc.edu>
>> Sent: Tuesday, July 7, 2015 7:18:04 AM
>> Subject: Re: [PATCH] [OPENMP] Initial support for '#pragma omp declare simd' directive.
>>
>> On Tue, Jul 7, 2015 at 7:40 AM, Bataev, Alexey <a.bataev at 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. :-)
> Okay, but this was not my point. I did not say it should be an error. Warnings are not for incorrect code, they are for correct code were we feel the user *probably* intended something else. If a function is marked with several identical 'omp declare simd' pragmas, is that likely to be intentional or a mistake of some kind?
>
> Even if we decide on a warning here, I'm fine with adding it in follow-up. I think it would need to account for the other clauses as well anyway.
>
> Thanks again,
> Hal
>
>>> #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.bataev at 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 at +1 {{expected an OpenMP directive}}
>>>> +#pragma omp declare
>>>> +
>>>> +// expected-error at +2 {{'#pragma omp declare simd' can be applied
>>>> to
>>>> functions or methods only}}
>>>> +#pragma omp declare simd
>>>> +int a;
>>>> +// expected-error at +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 at +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 at +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");
>>>





More information about the cfe-commits mailing list