DmitryPolukhin updated this revision to Diff 52070.
DmitryPolukhin added a comment.
- Added test for templates in declare target region
http://reviews.llvm.org/D18542
Files:
include/clang/AST/ASTMutationListener.h
include/clang/AST/Attr.h
include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/OpenMPKinds.def
include/clang/Sema/Sema.h
include/clang/Serialization/ASTWriter.h
lib/AST/ASTContext.cpp
lib/AST/DeclPrinter.cpp
lib/Basic/OpenMPKinds.cpp
lib/Frontend/MultiplexConsumer.cpp
lib/Parse/ParseOpenMP.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOpenMP.cpp
lib/Serialization/ASTCommon.h
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterDecl.cpp
test/OpenMP/declare_target_ast_print.cpp
test/OpenMP/declare_target_messages.cpp
utils/TableGen/ClangAttrEmitter.cpp
Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -30,28 +30,32 @@
namespace {
class FlattenedSpelling {
- std::string V, N, NS;
+ std::string V, N, NS, E;
bool K;
public:
FlattenedSpelling(const std::string &Variety, const std::string &Name,
- const std::string &Namespace, bool KnownToGCC) :
- V(Variety), N(Name), NS(Namespace), K(KnownToGCC) {}
+ const std::string &Namespace, const std::string &Ending,
+ bool KnownToGCC) :
+ V(Variety), N(Name), NS(Namespace), E(Ending), K(KnownToGCC) {}
explicit FlattenedSpelling(const Record &Spelling) :
V(Spelling.getValueAsString("Variety")),
N(Spelling.getValueAsString("Name")) {
assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been"
"flattened!");
if (V == "CXX11" || V == "Pragma")
NS = Spelling.getValueAsString("Namespace");
+ if (V == "Pragma")
+ E = Spelling.getValueAsString("Ending");
bool Unset;
K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset);
}
const std::string &variety() const { return V; }
const std::string &name() const { return N; }
const std::string &nameSpace() const { return NS; }
+ const std::string &ending() const { return E; }
bool knownToGCC() const { return K; }
};
} // end anonymous namespace
@@ -64,8 +68,8 @@
for (const auto &Spelling : Spellings) {
if (Spelling->getValueAsString("Variety") == "GCC") {
// Gin up two new spelling objects to add into the list.
- Ret.emplace_back("GNU", Spelling->getValueAsString("Name"), "", true);
- Ret.emplace_back("CXX11", Spelling->getValueAsString("Name"), "gnu",
+ Ret.emplace_back("GNU", Spelling->getValueAsString("Name"), "", "", true);
+ Ret.emplace_back("CXX11", Spelling->getValueAsString("Name"), "gnu", "",
true);
} else
Ret.push_back(FlattenedSpelling(*Spelling));
@@ -1259,6 +1263,63 @@
OS << "}\n\n";
}
+// Determines if an attribute has a Pragma spelling.
+static bool AttrHasPragmaSpelling(const Record *R) {
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
+ return std::find_if(Spellings.begin(), Spellings.end(),
+ [](const FlattenedSpelling &S) {
+ return S.variety() == "Pragma";
+ }) != Spellings.end();
+}
+
+static void
+writePrettyPrintEndFunction(Record &R,
+ const std::vector<std::unique_ptr<Argument>> &Args,
+ raw_ostream &OS) {
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
+
+ OS << "void " << R.getName() << "Attr::printPrettyEnd("
+ << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n";
+
+ if (!AttrHasPragmaSpelling(&R)) {
+ OS << "}\n\n";
+ return;
+ }
+
+ OS <<
+ " switch (SpellingListIndex) {\n"
+ " default:\n"
+ " llvm_unreachable(\"Unknown attribute spelling!\");\n"
+ " break;\n";
+
+ for (unsigned I = 0; I < Spellings.size(); ++ I) {
+ if (Spellings[I].variety() != "Pragma")
+ continue;
+
+ OS << " case " << I << " : {\n";
+ std::string Ending = Spellings[I].ending();
+ if (!Ending.empty()) {
+ llvm::SmallString<64> Spelling;
+ std::string Namespace = Spellings[I].nameSpace();
+ if (!Namespace.empty()) {
+ Spelling += Namespace;
+ Spelling += " ";
+ }
+ Spelling += Ending;
+
+ OS << " OS << \"#pragma " << Spelling << "\\n\";\n";
+
+ }
+ OS << " break;\n";
+ OS << " }\n";
+ }
+
+ // End of the switch statement.
+ OS << "}\n";
+ // End of the print function.
+ OS << "}\n\n";
+}
+
/// \brief Return the index of a spelling in a spelling list.
static unsigned
getSpellingListIndex(const std::vector<FlattenedSpelling> &SpellingList,
@@ -1642,6 +1703,8 @@
OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
OS << " void printPretty(raw_ostream &OS,\n"
<< " const PrintingPolicy &Policy) const;\n";
+ OS << " void printPrettyEnd(raw_ostream &OS,\n"
+ << " const PrintingPolicy &Policy) const;\n";
OS << " const char *getSpelling() const;\n";
if (!ElideSpelling) {
@@ -1714,6 +1777,7 @@
OS << " return A;\n}\n\n";
writePrettyPrintFunction(R, Args, OS);
+ writePrettyPrintEndFunction(R, Args, OS);
writeGetSpellingFunction(R, OS);
}
@@ -1744,6 +1808,10 @@
OS << "void Attr::printPretty(raw_ostream &OS, "
"const PrintingPolicy &Policy) const {\n";
EmitFunc("printPretty(OS, Policy)");
+
+ OS << "void Attr::printPrettyEnd(raw_ostream &OS, "
+ "const PrintingPolicy &Policy) const {\n";
+ EmitFunc("printPrettyEnd(OS, Policy)");
}
} // end namespace clang
@@ -1755,15 +1823,6 @@
}
}
-// Determines if an attribute has a Pragma spelling.
-static bool AttrHasPragmaSpelling(const Record *R) {
- std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
- return std::find_if(Spellings.begin(), Spellings.end(),
- [](const FlattenedSpelling &S) {
- return S.variety() == "Pragma";
- }) != Spellings.end();
-}
-
namespace {
struct AttrClassDescriptor {
const char * const MacroName;
Index: test/OpenMP/declare_target_messages.cpp
===================================================================
--- /dev/null
+++ test/OpenMP/declare_target_messages.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -fnoopenmp-use-tls -ferror-limit 100 -o - %s
+
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+
+int a, b; // expected-warning {{declaration is not declared in any declare target region}}
+__thread int t; // expected-note {{defined as threadprivate or thread local}}
+#pragma omp declare target private(a) // expected-warning {{extra tokens at the end of '#pragma omp declare target' are ignored}}
+void f();
+#pragma omp end declare target shared(a) // expected-warning {{extra tokens at the end of '#pragma omp end declare target' are ignored}}
+void c(); // expected-warning {{declaration is not declared in any declare target region}}
+
+extern int b;
+
+struct NonT {
+ int a;
+};
+
+typedef int sint;
+
+#pragma omp declare target // expected-note {{to match this '#pragma omp declare target'}}
+#pragma omp threadprivate(a) // expected-note {{defined as threadprivate or thread local}}
+extern int b;
+int g;
+
+struct T { // expected-note {{mappable type cannot be polymorphic}}
+ int a;
+ virtual int method();
+};
+
+class VC { // expected-note {{mappable type cannot be polymorphic}}
+ T member;
+ NonT member1;
+ public:
+ virtual int method() { T a; return 0; } // expected-error {{type 'T' is not mappable to target}}
+};
+
+struct C {
+ NonT a;
+ sint b;
+ int method();
+ int method1();
+};
+
+int C::method1() {
+ return 0;
+}
+
+void foo() {
+ a = 0; // expected-error {{threadprivate variables cannot be used in target constructs}}
+ b = 0; // expected-note {{used here}}
+ t = 1; // expected-error {{threadprivate variables cannot be used in target constructs}}
+ C object;
+ VC object1; // expected-error {{type 'VC' is not mappable to target}}
+ g = object.method();
+ g += object.method1();
+ g += object1.method();
+ f();
+ c(); // expected-note {{used here}}
+}
+#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}}
+void foo1() {}
+#pragma omp end declare target
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+
+int C::method() {
+ return 0;
+}
+
+struct S {
+#pragma omp declare target // expected-error {{directive must be at file or namespace scope}}
+ int v;
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+};
+
+int main (int argc, char **argv) {
+#pragma omp declare target // expected-error {{unexpected OpenMP directive '#pragma omp declare target'}}
+ int v;
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+ foo();
+ return (0);
+}
+
+namespace {
+#pragma omp declare target // expected-note {{to match this '#pragma omp declare target'}}
+ int x;
+} // expected-error {{expected '#pragma omp end declare target'}}
+#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+
+#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}} expected-note {{to match this '#pragma omp declare target'}}
Index: test/OpenMP/declare_target_ast_print.cpp
===================================================================
--- /dev/null
+++ test/OpenMP/declare_target_ast_print.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare target
+// CHECK: #pragma omp declare target
+void foo() {}
+// CHECK-NEXT: void foo()
+#pragma omp end declare target
+// CHECK: #pragma omp end declare target
+
+extern "C" {
+#pragma omp declare target
+// CHECK: #pragma omp declare target
+void foo_c() {}
+// CHECK-NEXT: void foo_c()
+#pragma omp end declare target
+// CHECK: #pragma omp end declare target
+}
+
+extern "C++" {
+#pragma omp declare target
+// CHECK: #pragma omp declare target
+void foo_cpp() {}
+// CHECK-NEXT: void foo_cpp()
+#pragma omp end declare target
+// CHECK: #pragma omp end declare target
+}
+
+#pragma omp declare target
+template <class T>
+struct C {
+// CHECK: template <class T = int> struct C
+ T t;
+// CHECK-NEXT: int t;
+ static T ts;
+// CHECK-NEXT: #pragma omp declare target
+// CHECK-NEXT: static int ts;
+// CHECK: #pragma omp end declare target
+
+ C(T t) : t(t) {
+ }
+// CHECK: #pragma omp declare target
+// CHECK-NEXT: C(int t) : t(t) {
+// CHECK-NEXT: }
+// CHECK: #pragma omp end declare target
+
+ T foo() {
+ return t;
+ }
+// CHECK: #pragma omp declare target
+// CHECK-NEXT: int foo() {
+// CHECK-NEXT: return this->t;
+// CHECK-NEXT: }
+// CHECK: #pragma omp end declare target
+};
+
+// CHECK: template <class T> struct C {
+// CHECK: #pragma omp declare target
+// CHECK-NEXT: static T ts;
+// CHECK-NEXT: #pragma omp end declare target
+
+template<class T>
+T C<T>::ts = 1;
+// CHECK: #pragma omp declare target
+// CHECK: T ts = 1;
+// CHECK: #pragma omp end declare target
+
+// CHECK: #pragma omp declare target
+// CHECK: int test1()
+int test1() {
+ C<int> c(1);
+ return c.foo() + c.ts;
+}
+#pragma omp end declare target
+// CHECK: #pragma omp end declare target
+
+int main (int argc, char **argv) {
+ foo();
+ foo_c();
+ foo_cpp();
+ test1();
+ return (0);
+}
+
+// CHECK: #pragma omp declare target
+// CHECK-NEXT: int ts = 1;
+// CHECK-NEXT: #pragma omp end declare target
+#endif
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -2129,8 +2129,10 @@
// An ObjCMethodDecl is never considered as "required" because its
// implementation container always is.
- // File scoped assembly or obj-c implementation must be seen.
- if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D))
+ // File scoped assembly or obj-c or OMP declare target implementation must be
+ // seen.
+ if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D) ||
+ D->hasAttr<OMPDeclareTargetDeclAttr>())
return true;
// ImportDecl is used by codegen to determine the set of imported modules to
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -4756,6 +4756,11 @@
Record);
break;
+ case UPD_DECL_MARKED_OPENMP_DECLARETARGET:
+ AddSourceRange(D->getAttr<OMPDeclareTargetDeclAttr>()->getRange(),
+ Record);
+ break;
+
case UPD_DECL_EXPORTED:
Record.push_back(getSubmoduleID(Update.getModule()));
break;
@@ -5885,6 +5890,14 @@
DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
}
+void ASTWriter::DeclarationMarkedOpenMPDeclareTarget(const Decl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_DECLARETARGET));
+}
+
void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {
assert(!WritingAST && "Already writing the AST!");
assert(D->isHidden() && "expected a hidden declaration");
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -3879,6 +3879,11 @@
Reader.Context, ReadSourceRange(Record, Idx)));
break;
+ case UPD_DECL_MARKED_OPENMP_DECLARETARGET:
+ D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(
+ Reader.Context, ReadSourceRange(Record, Idx)));
+ 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
@@ -37,6 +37,7 @@
UPD_MANGLING_NUMBER,
UPD_STATIC_LOCAL_NUMBER,
UPD_DECL_MARKED_OPENMP_THREADPRIVATE,
+ UPD_DECL_MARKED_OPENMP_DECLARETARGET,
UPD_DECL_EXPORTED,
UPD_ADDED_ATTR_TO_RECORD
};
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -641,6 +641,11 @@
return DVar;
}
+ if (Stack.size() == 1) {
+ // Not in OpenMP execution region and top scope was already checked.
+ return DVar;
+ }
+
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.4]
// Static data members are shared.
@@ -1701,6 +1706,8 @@
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_declare_reduction:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -3153,6 +3160,8 @@
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
break;
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
case OMPD_threadprivate:
case OMPD_declare_reduction:
llvm_unreachable("OpenMP Directive is not allowed");
@@ -10263,3 +10272,141 @@
return new (Context)
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
}
+
+bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) {
+ DeclContext *CurLexicalContext = getCurLexicalContext();
+ if (!CurLexicalContext->isFileContext() &&
+ !CurLexicalContext->isExternCContext() &&
+ !CurLexicalContext->isExternCXXContext()) {
+ Diag(Loc, diag::err_omp_region_not_file_context);
+ return false;
+ }
+ if (IsInOpenMPDeclareTargetContext) {
+ Diag(Loc, diag::err_omp_enclosed_declare_target);
+ return false;
+ }
+
+ IsInOpenMPDeclareTargetContext = true;
+ return true;
+}
+
+void Sema::ActOnFinishOpenMPDeclareTargetDirective() {
+ assert(IsInOpenMPDeclareTargetContext &&
+ "Unexpected ActOnFinishOpenMPDeclareTargetDirective");
+
+ IsInOpenMPDeclareTargetContext = false;
+}
+
+static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
+ Sema &SemaRef, Decl *D) {
+ if (!D)
+ return;
+ Decl *LD = nullptr;
+ if (isa<TagDecl>(D)) {
+ LD = cast<TagDecl>(D)->getDefinition();
+ } else if (isa<VarDecl>(D)) {
+ LD = cast<VarDecl>(D)->getDefinition();
+
+ // If this is an implicit variable that is legal and we do not need to do
+ // anything.
+ if (cast<VarDecl>(D)->isImplicit()) {
+ D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context));
+ if (auto *ML = SemaRef.Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(D);
+ return;
+ }
+
+ } else if (isa<FunctionDecl>(D)) {
+ const FunctionDecl *FD = nullptr;
+ if (cast<FunctionDecl>(D)->hasBody(FD))
+ LD = const_cast<FunctionDecl *>(FD);
+
+ // If the definition is associated with the current declaration in the
+ // target region (it can be e.g. a lambda) that is legal and we do not need
+ // to do anything else.
+ if (LD == D) {
+ D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context));
+ if (auto *ML = SemaRef.Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(D);
+ return;
+ }
+ }
+ if (!LD)
+ LD = D;
+ if (LD && !LD->hasAttr<OMPDeclareTargetDeclAttr>() &&
+ (isa<VarDecl>(LD) || isa<FunctionDecl>(LD))) {
+ // Outlined declaration is not declared target.
+ if (LD->isOutOfLine()) {
+ SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context);
+ SemaRef.Diag(SL, diag::note_used_here) << SR;
+ } else {
+ DeclContext *DC = LD->getDeclContext();
+ while (DC) {
+ if (isa<FunctionDecl>(DC) &&
+ cast<FunctionDecl>(DC)->hasAttr<OMPDeclareTargetDeclAttr>())
+ break;
+ DC = DC->getParent();
+ }
+ if (DC)
+ return;
+
+ // Is not declared in target context.
+ SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context);
+ SemaRef.Diag(SL, diag::note_used_here) << SR;
+ }
+ // Mark decl as declared target to prevent further diagnostic.
+ D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context));
+ if (auto *ML = SemaRef.Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(D);
+ }
+}
+
+static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
+ Sema &SemaRef, DSAStackTy *Stack,
+ ValueDecl *VD) {
+ if (VD->hasAttr<OMPDeclareTargetDeclAttr>())
+ return true;
+ if (!CheckTypeMappable(SL, SR, SemaRef, Stack, VD->getType()))
+ return false;
+ return true;
+}
+
+void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) {
+ if (!D || D->isInvalidDecl())
+ return;
+ SourceRange SR = E ? E->getSourceRange() : D->getSourceRange();
+ SourceLocation SL = E ? E->getLocStart() : D->getLocation();
+ // 2.10.6: threadprivate variable cannot appear in a declare target directive.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (DSAStack->isThreadPrivate(VD)) {
+ Diag(SL, diag::err_omp_threadprivate_in_target);
+ ReportOriginalDSA(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false));
+ return;
+ }
+ }
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ // Problem if any with var declared with incomplete type will be reported
+ // as normal, so no need to check it here.
+ if ((E || !VD->getType()->isIncompleteType()) &&
+ !checkValueDeclInTarget(SL, SR, *this, DSAStack, VD)) {
+ // Mark decl as declared target to prevent further diagnostic.
+ if (isa<VarDecl>(VD) || isa<FunctionDecl>(VD)) {
+ VD->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(Context));
+ if (auto *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(VD);
+ }
+ return;
+ }
+ }
+ if (!E) {
+ // Checking declaration inside declare target region.
+ if (!D->hasAttr<OMPDeclareTargetDeclAttr>() &&
+ (isa<VarDecl>(D) || isa<FunctionDecl>(D))) {
+ D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(Context));
+ if (auto *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(D);
+ }
+ return;
+ }
+ checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D);
+}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -13801,6 +13801,9 @@
static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
Decl *D, Expr *E, bool MightBeOdrUse) {
+ if (SemaRef.isInOpenMPDeclareTargetContext())
+ SemaRef.checkDeclIsAllowedInOpenMPTarget(E, D);
+
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
DoMarkVarDeclReferenced(SemaRef, Loc, Var, E);
return;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -5052,6 +5052,9 @@
CurContext->addHiddenDecl(New);
}
+ if (isInOpenMPDeclareTargetContext())
+ checkDeclIsAllowedInOpenMPTarget(nullptr, New);
+
return New;
}
Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -31,6 +31,8 @@
OMPD_cancellation = OMPD_unknown + 1,
OMPD_data,
OMPD_declare,
+ OMPD_end,
+ OMPD_end_declare,
OMPD_enter,
OMPD_exit,
OMPD_point,
@@ -51,6 +53,7 @@
.Case("cancellation", OMPD_cancellation)
.Case("data", OMPD_data)
.Case("declare", OMPD_declare)
+ .Case("end", OMPD_end)
.Case("enter", OMPD_enter)
.Case("exit", OMPD_exit)
.Case("point", OMPD_point)
@@ -65,6 +68,9 @@
static const unsigned F[][3] = {
{ OMPD_cancellation, OMPD_point, OMPD_cancellation_point },
{ OMPD_declare, OMPD_reduction, OMPD_declare_reduction },
+ { OMPD_declare, OMPD_target, OMPD_declare_target },
+ { OMPD_end, OMPD_declare, OMPD_end_declare },
+ { OMPD_end_declare, OMPD_target, OMPD_end_declare_target },
{ OMPD_target, OMPD_data, OMPD_target_data },
{ OMPD_target, OMPD_enter, OMPD_target_enter },
{ OMPD_target, OMPD_exit, OMPD_target_exit },
@@ -373,6 +379,53 @@
return Res;
}
break;
+ case OMPD_declare_target: {
+ SourceLocation DTLoc = ConsumeAnyToken();
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(OMPD_declare_target);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ }
+ // Skip the last annot_pragma_openmp_end.
+ ConsumeAnyToken();
+
+ if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc))
+ return DeclGroupPtrTy();
+
+ DKind = ParseOpenMPDirectiveKind(*this);
+ while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target &&
+ Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) {
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX11Attributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ ParseExternalDeclaration(attrs);
+ if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) {
+ TentativeParsingAction TPA(*this);
+ ConsumeToken();
+ DKind = ParseOpenMPDirectiveKind(*this);
+ if (DKind != OMPD_end_declare_target)
+ TPA.Revert();
+ else
+ TPA.Commit();
+ }
+ }
+
+ if (DKind == OMPD_end_declare_target) {
+ ConsumeAnyToken();
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(OMPD_end_declare_target);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ }
+ // Skip the last annot_pragma_openmp_end.
+ ConsumeAnyToken();
+ } else {
+ Diag(Tok, diag::err_expected_end_declare_target);
+ Diag(DTLoc, diag::note_matching) << "'#pragma omp declare target'";
+ }
+ Actions.ActOnFinishOpenMPDeclareTargetDirective();
+ return DeclGroupPtrTy();
+ }
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
@@ -408,6 +461,7 @@
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_distribute:
+ case OMPD_end_declare_target:
Diag(Tok, diag::err_omp_unexpected_directive)
<< getOpenMPDirectiveName(DKind);
break;
@@ -627,6 +681,12 @@
OMPDirectiveScope.Exit();
break;
}
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ 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/Frontend/MultiplexConsumer.cpp
===================================================================
--- lib/Frontend/MultiplexConsumer.cpp
+++ lib/Frontend/MultiplexConsumer.cpp
@@ -125,6 +125,7 @@
void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
void DeclarationMarkedUsed(const Decl *D) override;
void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+ void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) override;
void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
void AddedAttributeToRecord(const Attr *Attr,
const RecordDecl *Record) override;
@@ -219,6 +220,11 @@
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
}
+void MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareTarget(
+ const Decl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->DeclarationMarkedOpenMPDeclareTarget(D);
+}
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
@@ -545,6 +545,8 @@
break;
}
break;
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
case OMPD_unknown:
case OMPD_threadprivate:
case OMPD_section:
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -99,6 +99,7 @@
const TemplateArgumentList *Args = nullptr);
void prettyPrintAttributes(Decl *D);
void prettyPrintPragmas(Decl *D);
+ void prettyPrintEndPragmas(Decl *D);
void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
};
}
@@ -236,6 +237,27 @@
}
}
+void DeclPrinter::prettyPrintEndPragmas(Decl *D) {
+ if (Policy.PolishForDeclaration)
+ return;
+
+ if (D->hasAttrs()) {
+ AttrVec &Attrs = D->getAttrs();
+ for (auto *A : Attrs) {
+ switch (A->getKind()) {
+#define ATTR(X)
+#define PRAGMA_SPELLING_ATTR(X) case attr::X:
+#include "clang/Basic/AttrList.inc"
+ A->printPrettyEnd(Out, Policy);
+ Indent();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
void DeclPrinter::printDeclType(QualType T, StringRef DeclName, bool Pack) {
// Normally, a PackExpansionType is written as T[3]... (for instance, as a
// template argument), but if it is the type of a declaration, the ellipsis
@@ -358,6 +380,8 @@
if (Terminator)
Out << Terminator;
Out << "\n";
+
+ prettyPrintEndPragmas(*D);
}
if (!Decls.empty())
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -8505,6 +8505,9 @@
return false;
} else if (isa<PragmaCommentDecl>(D))
return true;
+ else if (isa<OMPThreadPrivateDecl>(D) ||
+ D->hasAttr<OMPDeclareTargetDeclAttr>())
+ return true;
else if (isa<PragmaDetectMismatchDecl>(D))
return true;
else if (isa<OMPThreadPrivateDecl>(D))
Index: include/clang/Serialization/ASTWriter.h
===================================================================
--- include/clang/Serialization/ASTWriter.h
+++ include/clang/Serialization/ASTWriter.h
@@ -859,6 +859,7 @@
const ObjCInterfaceDecl *IFD) override;
void DeclarationMarkedUsed(const Decl *D) override;
void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+ void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) override;
void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
void AddedAttributeToRecord(const Attr *Attr,
const RecordDecl *Record) override;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -7826,6 +7826,8 @@
//
private:
void *VarDataSharingAttributesStack;
+ /// Set to true inside '#pragma omp declare target' region.
+ bool IsInOpenMPDeclareTargetContext = false;
/// \brief Initialization of data-sharing attributes stack.
void InitDataSharingAttributesStack();
void DestroyDataSharingAttributesStack();
@@ -7911,6 +7913,17 @@
DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd(
Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid);
+ /// Called on the start of target region i.e. '#pragma omp declare target'.
+ bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc);
+ /// Called at the end of target region i.e. '#pragme omp end declare target'.
+ void ActOnFinishOpenMPDeclareTargetDirective();
+ /// Check declaration inside target region.
+ void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D);
+ /// Return true inside OpenMP target region.
+ bool isInOpenMPDeclareTargetContext() {
+ return IsInOpenMPDeclareTargetContext;
+ }
+
/// \brief Initialization of captured region for OpenMP region.
void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);
/// \brief End of OpenMP region.
Index: include/clang/Basic/OpenMPKinds.def
===================================================================
--- include/clang/Basic/OpenMPKinds.def
+++ include/clang/Basic/OpenMPKinds.def
@@ -159,6 +159,8 @@
OPENMP_DIRECTIVE(taskloop)
OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd")
OPENMP_DIRECTIVE(distribute)
+OPENMP_DIRECTIVE_EXT(declare_target, "declare target")
+OPENMP_DIRECTIVE_EXT(end_declare_target, "end declare target")
// OpenMP clauses.
OPENMP_CLAUSE(if, OMPIfClause)
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7813,6 +7813,8 @@
"arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">;
def err_omp_ref_type_arg : Error<
"arguments of '#pragma omp %0' cannot be of reference type %1">;
+def err_omp_region_not_file_context : Error<
+ "directive must be at file or namespace scope">;
def err_omp_var_scope : Error<
"'#pragma omp %0' must appear in the scope of the %q1 variable declaration">;
def err_omp_var_used : Error<
@@ -7888,6 +7890,8 @@
def err_omp_not_integral : Error<
"expression must have integral or unscoped enumeration "
"type, not %0">;
+def err_omp_threadprivate_in_target : Error<
+ "threadprivate variables cannot be used in target constructs">;
def err_omp_incomplete_type : Error<
"expression has incomplete class type %0">;
def err_omp_explicit_conversion : Error<
@@ -7914,6 +7918,11 @@
def warn_omp_alignment_not_power_of_two : Warning<
"aligned clause will be ignored because the requested alignment is not a power of 2">,
InGroup<OpenMPClauses>;
+def err_omp_enclosed_declare_target : Error<
+ "declare target region may not be enclosed into another declare target region">;
+def warn_omp_not_in_target_context : Warning<
+ "declaration is not declared in any declare target region">,
+ InGroup<OpenMPTarget>;
def err_omp_aligned_expected_array_or_ptr : Error<
"argument of aligned clause should be array"
"%select{ or pointer|, pointer, reference to array or reference to pointer}1"
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -959,6 +959,8 @@
"incorrect map type modifier, expected 'always'">;
def err_omp_map_type_missing : Error<
"missing map type">;
+def err_expected_end_declare_target : Error<
+ "expected '#pragma omp end declare target'">;
// Pragma loop support.
def err_pragma_loop_missing_argument : Error<
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -819,6 +819,7 @@
def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
def OpenMPClauses : DiagGroup<"openmp-clauses">;
def OpenMPLoopForm : DiagGroup<"openmp-loop-form">;
+def OpenMPTarget : DiagGroup<"openmp-target">;
// Backend warnings.
def BackendInlineAsm : DiagGroup<"inline-asm">;
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -202,8 +202,10 @@
int Version = version;
}
class Keyword<string name> : Spelling<name, "Keyword">;
-class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
+class Pragma<string namespace, string name, string ending = "">
+ : Spelling<name, "Pragma"> {
string Namespace = namespace;
+ string Ending = ending;
}
// The GCC spelling implies GNU<name, "GNU"> and CXX11<"gnu", name> and also
@@ -2244,6 +2246,16 @@
let Documentation = [Undocumented];
}
+def OMPDeclareTargetDecl : Attr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [Pragma<"omp", "declare target", "end declare target">];
+ let SemaHandler = 0;
+ let Documentation = [Undocumented];
+ let AdditionalMembers = [{
+ void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {}
+ }];
+}
+
def InternalLinkage : InheritableAttr {
let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">];
let Subjects = SubjectList<[Var, Function, CXXRecord]>;
Index: include/clang/AST/Attr.h
===================================================================
--- include/clang/AST/Attr.h
+++ include/clang/AST/Attr.h
@@ -112,6 +112,9 @@
// Pretty print this attribute.
void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
+ // Pretty print this attribute ending text if any.
+ void printPrettyEnd(raw_ostream &OS, const PrintingPolicy &Policy) const;
+
/// \brief By default, attributes cannot be duplicated when being merged;
/// however, an attribute can override this. Returns true if the attribute
/// can be duplicated when merging.
Index: include/clang/AST/ASTMutationListener.h
===================================================================
--- include/clang/AST/ASTMutationListener.h
+++ include/clang/AST/ASTMutationListener.h
@@ -107,6 +107,12 @@
/// \param D the declaration marked OpenMP threadprivate.
virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {}
+ /// \brief A declaration is marked as OpenMP declaretarget which was not
+ /// previously marked as declaretarget.
+ ///
+ /// \param D the declaration marked OpenMP declaretarget.
+ virtual void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) {}
+
/// \brief A definition has been made visible by being redefined locally.
///
/// \param D The definition that was previously not visible.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits