On Tue, Jul 7, 2015 at 8:35 AM, Hal Finkel <hfin...@anl.gov> wrote: > ----- 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.
My acquiescence is because the standard says it's a well-formed construct, and I'm somewhat hesitant to diagnose on well-formed, benign code. But I also agree with your logic on whether this is code the user intended or not. I suspect with macros, intention becomes slightly more muddy. Btw, is this expected to work? // a.h #pragma omp declare simd // a.cpp #include "a.h" void f() {} ~Aaron > > 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