----- Original Message ----- > From: "Alexey Bataev" <a.bat...@hotmail.com> > To: "Hal Finkel" <hfin...@anl.gov>, "Aaron Ballman" <aaron.ball...@gmail.com> > Cc: reviews+d10599+public+2871690e17faf...@reviews.llvm.org, "Richard Smith" > <rich...@metafoo.co.uk>, > ejstot...@gmail.com, fraggamuf...@gmail.com, "llvm cfe" > <cfe-commits@cs.uiuc.edu> > Sent: Tuesday, July 7, 2015 7:52:02 AM > Subject: Re: [PATCH] [OPENMP] Initial support for '#pragma omp declare simd' > directive. > > 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. :)
Let's wait and think about it :) My underlying thought is that a warning will catch cases where the user intended to declare the function for, say, 2 different simd lengths, but actually just repeated one simd length twice. Regardless, let's revisit this once we have support for some clauses here. Thanks again, Hal > > Best regards, > Alexey Bataev > ============= > Software Engineer > Intel Compiler Team > > 07.07.2015 15:35, Hal Finkel пишет: > > ----- Original Message ----- > >> From: "Aaron Ballman" <aaron.ball...@gmail.com> > >> To: "Alexey Bataev" <a.bat...@hotmail.com> > >> Cc: reviews+d10599+public+2871690e17faf...@reviews.llvm.org, > >> "Richard Smith" <rich...@metafoo.co.uk>, "Hal Finkel" > >> <hfin...@anl.gov>, ejstot...@gmail.com, fraggamuf...@gmail.com, > >> "llvm cfe" <cfe-commits@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.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. :-) > > 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.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"); > >>> > > -- Hal Finkel Assistant Computational Scientist Leadership Computing Facility Argonne National Laboratory _______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits