6 changes: 5 additions & 1 deletion clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ static const Stmt *getSingleCompoundChild(ASTContext &Ctx, const Stmt *Body) {
isa<PragmaDetectMismatchDecl>(D) || isa<UsingDecl>(D) ||
isa<UsingDirectiveDecl>(D) ||
isa<OMPDeclareReductionDecl>(D) ||
isa<OMPThreadPrivateDecl>(D))
isa<OMPThreadPrivateDecl>(D) || isa<OMPAllocateDecl>(D))
return true;
const auto *VD = dyn_cast<VarDecl>(D);
if (!VD)
Expand Down Expand Up @@ -835,6 +835,7 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx,
case OMPD_cancellation_point:
case OMPD_ordered:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_task:
case OMPD_simd:
case OMPD_sections:
Expand Down Expand Up @@ -904,6 +905,7 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
case OMPD_cancellation_point:
case OMPD_ordered:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_task:
case OMPD_simd:
case OMPD_sections:
Expand Down Expand Up @@ -1055,6 +1057,7 @@ static bool hasNestedLightweightDirective(ASTContext &Ctx,
case OMPD_cancellation_point:
case OMPD_ordered:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_task:
case OMPD_simd:
case OMPD_sections:
Expand Down Expand Up @@ -1129,6 +1132,7 @@ static bool supportsLightweightRuntime(ASTContext &Ctx,
case OMPD_cancellation_point:
case OMPD_ordered:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_task:
case OMPD_simd:
case OMPD_sections:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3963,6 +3963,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_nowait:
case OMPC_untied:
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_depend:
case OMPC_mergeable:
case OMPC_device:
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5062,6 +5062,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
EmitOMPThreadPrivateDecl(cast<OMPThreadPrivateDecl>(D));
break;

case Decl::OMPAllocate:
break;

case Decl::OMPDeclareReduction:
EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(D));
break;
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Frontend/MultiplexConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class MultiplexASTMutationListener : public ASTMutationListener {
const ObjCInterfaceDecl *IFD) override;
void DeclarationMarkedUsed(const Decl *D) override;
void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
void DeclarationMarkedOpenMPAllocate(const Decl *D, const Attr *A) override;
void DeclarationMarkedOpenMPDeclareTarget(const Decl *D,
const Attr *Attr) override;
void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
Expand Down Expand Up @@ -208,6 +209,11 @@ void MultiplexASTMutationListener::DeclarationMarkedOpenMPThreadPrivate(
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
}
void MultiplexASTMutationListener::DeclarationMarkedOpenMPAllocate(
const Decl *D, const Attr *A) {
for (ASTMutationListener *L : Listeners)
L->DeclarationMarkedOpenMPAllocate(D, A);
}
void MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareTarget(
const Decl *D, const Attr *Attr) {
for (auto *L : Listeners)
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1734,7 +1734,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
/// [C++11] attribute-specifier-seq decl-specifier-seq[opt]
/// init-declarator-list ';'
///[C90/C++]init-declarator-list ';' [TODO]
/// [OMP] threadprivate-directive [TODO]
/// [OMP] threadprivate-directive
/// [OMP] allocate-directive [TODO]
///
/// for-range-declaration: [C++11 6.5p1: stmt.ranged]
/// attribute-specifier-seq[opt] type-specifier-seq declarator
Expand Down
76 changes: 66 additions & 10 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,17 @@ enum OpenMPDirectiveKindEx {
OMPD_mapper,
};

class ThreadprivateListParserHelper final {
class DeclDirectiveListParserHelper final {
SmallVector<Expr *, 4> Identifiers;
Parser *P;
OpenMPDirectiveKind Kind;

public:
ThreadprivateListParserHelper(Parser *P) : P(P) {}
DeclDirectiveListParserHelper(Parser *P, OpenMPDirectiveKind Kind)
: P(P), Kind(Kind) {}
void operator()(CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {
ExprResult Res =
P->getActions().ActOnOpenMPIdExpression(P->getCurScope(), SS, NameInfo);
ExprResult Res = P->getActions().ActOnOpenMPIdExpression(
P->getCurScope(), SS, NameInfo, Kind);
if (Res.isUsable())
Identifiers.push_back(Res.get());
}
Expand Down Expand Up @@ -839,6 +841,10 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
/// annot_pragma_openmp 'threadprivate' simple-variable-list
/// annot_pragma_openmp_end
///
/// allocate-directive:
/// annot_pragma_openmp 'allocate' simple-variable-list
/// annot_pragma_openmp_end
///
/// declare-reduction-directive:
/// annot_pragma_openmp 'declare' 'reduction' [...]
/// annot_pragma_openmp_end
Expand Down Expand Up @@ -869,13 +875,14 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
switch (DKind) {
case OMPD_threadprivate: {
ConsumeToken();
ThreadprivateListParserHelper Helper(this);
if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Helper, true)) {
DeclDirectiveListParserHelper Helper(this, DKind);
if (!ParseOpenMPSimpleVarList(DKind, Helper,
/*AllowScopeSpecifier=*/true)) {
// The last seen token is annot_pragma_openmp_end - need to check for
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
<< getOpenMPDirectiveName(OMPD_threadprivate);
<< getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
// Skip the last annot_pragma_openmp_end.
Expand All @@ -885,6 +892,24 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
}
break;
}
case OMPD_allocate: {
ConsumeToken();
DeclDirectiveListParserHelper Helper(this, DKind);
if (!ParseOpenMPSimpleVarList(DKind, Helper,
/*AllowScopeSpecifier=*/true)) {
// The last seen token is annot_pragma_openmp_end - need to check for
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
<< getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
// Skip the last annot_pragma_openmp_end.
ConsumeAnnotationToken();
return Actions.ActOnOpenMPAllocateDirective(Loc, Helper.getIdentifiers());
}
break;
}
case OMPD_requires: {
SourceLocation StartLoc = ConsumeToken();
SmallVector<OMPClause *, 5> Clauses;
Expand Down Expand Up @@ -1098,6 +1123,10 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
/// annot_pragma_openmp 'threadprivate' simple-variable-list
/// annot_pragma_openmp_end
///
/// allocate-directive:
/// annot_pragma_openmp 'allocate' simple-variable-list
/// annot_pragma_openmp_end
///
/// declare-reduction-directive:
/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':'
/// <type> {',' <type>} ':' <expression> ')' ['initializer' '('
Expand Down Expand Up @@ -1157,13 +1186,14 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
<< getOpenMPDirectiveName(DKind) << 0;
}
ConsumeToken();
ThreadprivateListParserHelper Helper(this);
if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Helper, false)) {
DeclDirectiveListParserHelper Helper(this, DKind);
if (!ParseOpenMPSimpleVarList(DKind, Helper,
/*AllowScopeSpecifier=*/false)) {
// The last seen token is annot_pragma_openmp_end - need to check for
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
<< getOpenMPDirectiveName(OMPD_threadprivate);
<< getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
DeclGroupPtrTy Res = Actions.ActOnOpenMPThreadprivateDirective(
Expand All @@ -1173,6 +1203,31 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
SkipUntil(tok::annot_pragma_openmp_end);
break;
}
case OMPD_allocate: {
// FIXME: Should this be permitted in C++?
if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) ==
ParsedStmtContext()) {
Diag(Tok, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind) << 0;
}
ConsumeToken();
DeclDirectiveListParserHelper Helper(this, DKind);
if (!ParseOpenMPSimpleVarList(DKind, Helper,
/*AllowScopeSpecifier=*/false)) {
// The last seen token is annot_pragma_openmp_end - need to check for
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
<< getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
DeclGroupPtrTy Res =
Actions.ActOnOpenMPAllocateDirective(Loc, Helper.getIdentifiers());
Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
}
SkipUntil(tok::annot_pragma_openmp_end);
break;
}
case OMPD_declare_reduction:
ConsumeToken();
if (DeclGroupPtrTy Res =
Expand Down Expand Up @@ -1602,6 +1657,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
break;
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_uniform:
if (!WrongDirective)
Diag(Tok, diag::err_omp_unexpected_clause)
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,8 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
/// declaration: [C99 6.7]
/// declaration-specifiers init-declarator-list[opt] ';'
/// [!C99] init-declarator-list ';' [TODO: warn in c99 mode]
/// [OMP] threadprivate-directive [TODO]
/// [OMP] threadprivate-directive
/// [OMP] allocate-directive [TODO]
///
Parser::DeclGroupPtrTy
Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
Expand Down
75 changes: 64 additions & 11 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1908,7 +1908,8 @@ class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback {
explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {}
bool ValidateCandidate(const TypoCorrection &Candidate) override {
NamedDecl *ND = Candidate.getCorrectionDecl();
if (ND && (isa<VarDecl>(ND) || isa<FunctionDecl>(ND))) {
if (ND && ((isa<VarDecl>(ND) && ND->getKind() == Decl::Var) ||
isa<FunctionDecl>(ND))) {
return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(),
SemaRef.getCurScope());
}
Expand All @@ -1920,7 +1921,8 @@ class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback {

ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
const DeclarationNameInfo &Id) {
const DeclarationNameInfo &Id,
OpenMPDirectiveKind Kind) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);

Expand Down Expand Up @@ -1953,9 +1955,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,

// OpenMP [2.9.2, Syntax, C/C++]
// Variables must be file-scope, namespace-scope, or static block-scope.
if (!VD->hasGlobalStorage()) {
if (Kind == OMPD_threadprivate && !VD->hasGlobalStorage()) {
Diag(Id.getLoc(), diag::err_omp_global_var_arg)
<< getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal();
<< getOpenMPDirectiveName(Kind) << !VD->isStaticLocal();
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
Expand All @@ -1972,7 +1974,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->getDeclContext()->isTranslationUnit() &&
!getCurLexicalContext()->isTranslationUnit()) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
<< getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
Expand All @@ -1987,7 +1989,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->isStaticDataMember() &&
!CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
<< getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
Expand All @@ -2003,7 +2005,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
(!getCurLexicalContext()->isFileContext() ||
!getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
<< getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
Expand All @@ -2014,10 +2016,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// OpenMP [2.9.2, Restrictions, C/C++, p.6]
// A threadprivate directive for static block-scope variables must appear
// in the scope of the variable and not in a nested scope.
if (CanonicalVD->isStaticLocal() && CurScope &&
if (CanonicalVD->isLocalVarDecl() && CurScope &&
!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
<< getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
Expand All @@ -2029,9 +2031,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
// A threadprivate directive must lexically precede all references to any
// of the variables in its list.
if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) {
if (Kind == OMPD_threadprivate && VD->isUsed() &&
!DSAStack->isThreadPrivate(VD)) {
Diag(Id.getLoc(), diag::err_omp_var_used)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
<< getOpenMPDirectiveName(Kind) << VD;
return ExprError();
}

Expand Down Expand Up @@ -2163,6 +2166,41 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
return D;
}

Sema::DeclGroupPtrTy
Sema::ActOnOpenMPAllocateDirective(SourceLocation Loc, ArrayRef<Expr *> VarList,
DeclContext *Owner) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
auto *DE = cast<DeclRefExpr>(RefExpr);
auto *VD = cast<VarDecl>(DE->getDecl());

// Check if this is a TLS variable or global register.
if (VD->getTLSKind() != VarDecl::TLS_None ||
VD->hasAttr<OMPThreadPrivateDeclAttr>() ||
(VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() &&
!VD->isLocalVarDecl()))
continue;
// Do not apply for parameters.
if (isa<ParmVarDecl>(VD))
continue;

Vars.push_back(RefExpr);
VD->addAttr(
OMPAllocateDeclAttr::CreateImplicit(Context, DE->getSourceRange()));
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPAllocate(VD,
VD->getAttr<OMPAllocateDeclAttr>());
}
if (Vars.empty())
return nullptr;
if (!Owner)
Owner = getCurLexicalContext();
OMPAllocateDecl *D = OMPAllocateDecl::Create(Context, Owner, Loc, Vars);
D->setAccess(AS_public);
Owner->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}

Sema::DeclGroupPtrTy
Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
Expand Down Expand Up @@ -2863,6 +2901,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
break;
}
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
Expand Down Expand Up @@ -3719,6 +3758,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
Expand Down Expand Up @@ -8398,6 +8438,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
Expand Down Expand Up @@ -8482,6 +8523,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
// Do not capture if-clause expressions.
break;
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
Expand Down Expand Up @@ -8549,6 +8591,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
Expand Down Expand Up @@ -8617,6 +8660,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
Expand Down Expand Up @@ -8682,6 +8726,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
Expand Down Expand Up @@ -8748,6 +8793,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
Expand Down Expand Up @@ -8813,6 +8859,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
Expand Down Expand Up @@ -8877,6 +8924,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
Expand Down Expand Up @@ -8928,6 +8976,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
Expand Down Expand Up @@ -9251,6 +9300,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
Expand Down Expand Up @@ -9428,6 +9478,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
Expand Down Expand Up @@ -9645,6 +9696,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_default:
case OMPC_proc_bind:
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
case OMPC_depend:
case OMPC_device:
Expand Down Expand Up @@ -9841,6 +9893,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_read:
case OMPC_write:
case OMPC_update:
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2876,6 +2876,21 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
return TD;
}

Decl *TemplateDeclInstantiator::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
SmallVector<Expr *, 5> Vars;
for (auto *I : D->varlists()) {
Expr *Var = SemaRef.SubstExpr(I, TemplateArgs).get();
assert(isa<DeclRefExpr>(Var) && "allocate arg is not a DeclRefExpr");
Vars.push_back(Var);
}

Sema::DeclGroupPtrTy Res =
SemaRef.ActOnOpenMPAllocateDirective(D->getLocation(), Vars, Owner);
if (Res.get().isNull())
return nullptr;
return Res.get().getSingleDecl();
}

Decl *TemplateDeclInstantiator::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
llvm_unreachable(
"Requires directive cannot be instantiated within a dependent context");
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::OMPAllocate:
case Decl::OMPRequires:
case Decl::OMPCapturedExpr:
case Decl::OMPDeclareReduction:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ enum DeclUpdateKind {
UPD_MANGLING_NUMBER,
UPD_STATIC_LOCAL_NUMBER,
UPD_DECL_MARKED_OPENMP_THREADPRIVATE,
UPD_DECL_MARKED_OPENMP_ALLOCATE,
UPD_DECL_MARKED_OPENMP_DECLARETARGET,
UPD_DECL_EXPORTED,
UPD_ADDED_ATTR_TO_RECORD
Expand Down
22 changes: 21 additions & 1 deletion clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ namespace clang {
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void VisitOMPAllocateDecl(OMPAllocateDecl *D);
void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
void VisitOMPRequiresDecl(OMPRequiresDecl *D);
Expand Down Expand Up @@ -2633,6 +2634,17 @@ void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
D->setVars(Vars);
}

void ASTDeclReader::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
VisitDecl(D);
unsigned NumVars = D->varlist_size();
SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i) {
Vars.push_back(Record.readExpr());
}
D->setVars(Vars);
}

void ASTDeclReader::VisitOMPRequiresDecl(OMPRequiresDecl * D) {
VisitDecl(D);
unsigned NumClauses = D->clauselist_size();
Expand Down Expand Up @@ -2795,7 +2807,7 @@ static bool isConsumerInterestedIn(ASTContext &Ctx, Decl *D, bool HasBody) {
isa<PragmaDetectMismatchDecl>(D))
return true;
if (isa<OMPThreadPrivateDecl>(D) || isa<OMPDeclareReductionDecl>(D) ||
isa<OMPDeclareMapperDecl>(D))
isa<OMPDeclareMapperDecl>(D) || isa<OMPAllocateDecl>(D))
return !D->getDeclContext()->isFunctionOrMethod();
if (const auto *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() &&
Expand Down Expand Up @@ -3866,6 +3878,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_OMP_THREADPRIVATE:
D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record.readInt());
break;
case DECL_OMP_ALLOCATE:
D = OMPAllocateDecl::CreateDeserialized(Context, ID, Record.readInt());
break;
case DECL_OMP_REQUIRES:
D = OMPRequiresDecl::CreateDeserialized(Context, ID, Record.readInt());
break;
Expand Down Expand Up @@ -4465,6 +4480,11 @@ void ASTDeclReader::UpdateDecl(Decl *D,
ReadSourceRange()));
break;

case UPD_DECL_MARKED_OPENMP_ALLOCATE:
D->addAttr(OMPAllocateDeclAttr::CreateImplicit(Reader.getContext(),
ReadSourceRange()));
break;

case UPD_DECL_EXPORTED: {
unsigned SubmoduleID = readSubmoduleID();
auto *Exported = cast<NamedDecl>(D);
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_PRAGMA_COMMENT);
RECORD(DECL_PRAGMA_DETECT_MISMATCH);
RECORD(DECL_OMP_DECLARE_REDUCTION);
RECORD(DECL_OMP_ALLOCATE);

// Statements and Exprs can occur in the Decls and Types block.
AddStmtsExprs(Stream, Record);
Expand Down Expand Up @@ -5287,6 +5288,10 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
D->getAttr<OMPThreadPrivateDeclAttr>()->getRange());
break;

case UPD_DECL_MARKED_OPENMP_ALLOCATE:
Record.AddSourceRange(D->getAttr<OMPAllocateDeclAttr>()->getRange());
break;

case UPD_DECL_MARKED_OPENMP_DECLARETARGET:
Record.push_back(D->getAttr<OMPDeclareTargetDeclAttr>()->getMapType());
Record.AddSourceRange(
Expand Down Expand Up @@ -6404,6 +6409,15 @@ void ASTWriter::DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {
DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
}

void ASTWriter::DeclarationMarkedOpenMPAllocate(const Decl *D, const Attr *A) {
if (Chain && Chain->isProcessingUpdateRecords()) return;
assert(!WritingAST && "Already writing the AST!");
if (!D->isFromASTFile())
return;

DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_ALLOCATE, A));
}

void ASTWriter::DeclarationMarkedOpenMPDeclareTarget(const Decl *D,
const Attr *Attr) {
if (Chain && Chain->isProcessingUpdateRecords()) return;
Expand Down
11 changes: 10 additions & 1 deletion clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ namespace clang {
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void VisitOMPAllocateDecl(OMPAllocateDecl *D);
void VisitOMPRequiresDecl(OMPRequiresDecl *D);
void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
Expand Down Expand Up @@ -1744,10 +1745,18 @@ void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
Code = serialization::DECL_OMP_THREADPRIVATE;
}

void ASTDeclWriter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
Record.push_back(D->varlist_size());
VisitDecl(D);
for (auto *I : D->varlists())
Record.AddStmt(I);
Code = serialization::DECL_OMP_ALLOCATE;
}

void ASTDeclWriter::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
Record.push_back(D->clauselist_size());
VisitDecl(D);
OMPClauseWriter ClauseWriter(Record);
OMPClauseWriter ClauseWriter(Record);
for (OMPClause *C : D->clauselists())
ClauseWriter.writeClause(C);
Code = serialization::DECL_OMP_REQUIRES;
Expand Down
79 changes: 79 additions & 0 deletions clang/test/OpenMP/allocate_ast_print.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// RUN: %clang_cc1 -verify -fopenmp -triple x86_64-apple-darwin10.6.0 -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp -triple x86_64-apple-darwin10.6.0 -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -triple x86_64-apple-darwin10.6.0 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print
// RUN: %clang_cc1 -verify -fopenmp -triple x86_64-unknown-linux-gnu -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -triple x86_64-unknown-linux-gnu -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -triple x86_64-unknown-linux-gnu -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print

// RUN: %clang_cc1 -verify -fopenmp-simd -triple x86_64-apple-darwin10.6.0 -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp-simd -triple x86_64-apple-darwin10.6.0 -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp-simd -triple x86_64-apple-darwin10.6.0 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print
// RUN: %clang_cc1 -verify -fopenmp-simd -triple x86_64-unknown-linux-gnu -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp-simd -fnoopenmp-use-tls -triple x86_64-unknown-linux-gnu -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp-simd -fnoopenmp-use-tls -triple x86_64-unknown-linux-gnu -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print
// expected-no-diagnostics

#ifndef HEADER
#define HEADER

struct St{
int a;
};

struct St1{
int a;
static int b;
// CHECK: static int b;
#pragma omp allocate(b)
// CHECK-NEXT: #pragma omp allocate(St1::b){{$}}
} d;

int a, b;
// CHECK: int a;
// CHECK: int b;
#pragma omp allocate(a)
#pragma omp allocate(a)
// CHECK-NEXT: #pragma omp allocate(a)
// CHECK-NEXT: #pragma omp allocate(a)
#pragma omp allocate(d, b)
// CHECK-NEXT: #pragma omp allocate(d,b)

template <class T>
struct ST {
static T m;
#pragma omp allocate(m)
};

template <class T> T foo() {
T v;
#pragma omp allocate(v)
v = ST<T>::m;
return v;
}
//CHECK: template <class T> T foo() {
//CHECK-NEXT: T v;
//CHECK-NEXT: #pragma omp allocate(v)
//CHECK: template<> int foo<int>() {
//CHECK-NEXT: int v;
//CHECK-NEXT: #pragma omp allocate(v)

namespace ns{
int a;
}
// CHECK: namespace ns {
// CHECK-NEXT: int a;
// CHECK-NEXT: }
#pragma omp allocate(ns::a)
// CHECK-NEXT: #pragma omp allocate(ns::a)

int main () {
static int a;
// CHECK: static int a;
#pragma omp allocate(a)
// CHECK-NEXT: #pragma omp allocate(a)
a=2;
return (foo<int>());
}

extern template int ST<int>::m;
#endif
149 changes: 149 additions & 0 deletions clang/test/OpenMP/allocate_messages.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -fnoopenmp-use-tls -ferror-limit 100 -emit-llvm -o - %s
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -emit-llvm -o - %s

// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp-simd -fnoopenmp-use-tls -ferror-limit 100 -emit-llvm -o - %s
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp-simd -ferror-limit 100 -emit-llvm -o - %s

#pragma omp allocate // expected-error {{expected '(' after 'allocate'}}
#pragma omp allocate( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp allocate() // expected-error {{expected identifier}}
#pragma omp allocate(1) // expected-error {{expected unqualified-id}}
struct CompleteSt {
int a;
};

struct CompleteSt1 {
#pragma omp allocate(1) // expected-error {{expected unqualified-id}}
int a;
} d; // expected-note {{'d' defined here}}

int a; // expected-note {{'a' defined here}}

#pragma omp allocate(a)
#pragma omp allocate(u) // expected-error {{use of undeclared identifier 'u'}}
#pragma omp allocate(d, a)
int foo() { // expected-note {{declared here}}
static int l;
#pragma omp allocate(l)) // expected-warning {{extra tokens at the end of '#pragma omp allocate' are ignored}}
return (a);
}

#pragma omp allocate(a)(
// expected-warning@-1 {{extra tokens at the end of '#pragma omp allocate' are ignored}}
#pragma omp allocate(a)[ // expected-warning {{extra tokens at the end of '#pragma omp allocate' are ignored}}
#pragma omp allocate(a) { // expected-warning {{extra tokens at the end of '#pragma omp allocate' are ignored}}
#pragma omp allocate(a)) // expected-warning {{extra tokens at the end of '#pragma omp allocate' are ignored}}
#pragma omp allocate(a)] // expected-warning {{extra tokens at the end of '#pragma omp allocate' are ignored}}
#pragma omp allocate(a) } // expected-warning {{extra tokens at the end of '#pragma omp allocate' are ignored}}
#pragma omp allocate a // expected-error {{expected '(' after 'allocate'}}
#pragma omp allocate(d // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp allocate(d)) // expected-warning {{extra tokens at the end of '#pragma omp allocate' are ignored}}
int x, y;
#pragma omp allocate(x)) // expected-warning {{extra tokens at the end of '#pragma omp allocate' are ignored}}
#pragma omp allocate(y)),
// expected-warning@-1 {{extra tokens at the end of '#pragma omp allocate' are ignored}}
#pragma omp allocate(a, d)
#pragma omp allocate(d.a) // expected-error {{expected identifier}}
#pragma omp allocate((float)a) // expected-error {{expected unqualified-id}}
int foa; // expected-note {{'foa' declared here}}
#pragma omp allocate(faa) // expected-error {{use of undeclared identifier 'faa'; did you mean 'foa'?}}
#pragma omp allocate(foo) // expected-error {{'foo' is not a global variable, static local variable or static data member}}
#pragma omp allocate(int a = 2) // expected-error {{expected unqualified-id}}

struct IncompleteSt;

extern IncompleteSt e;
#pragma omp allocate(e)

int &f = a;
#pragma omp allocate(f)

class TestClass {
private:
int a; // expected-note {{declared here}}
static int b; // expected-note {{'b' declared here}}
TestClass() : a(0) {}

public:
TestClass(int aaa) : a(aaa) {}
#pragma omp allocate(b, a) // expected-error {{'a' is not a global variable, static local variable or static data member}}
} g(10);
#pragma omp allocate(b) // expected-error {{use of undeclared identifier 'b'}}
#pragma omp allocate(TestClass::b) // expected-error {{'#pragma omp allocate' must appear in the scope of the 'TestClass::b' variable declaration}}
#pragma omp allocate(g)

namespace ns {
int m;
#pragma omp allocate(m, m)
} // namespace ns
#pragma omp allocate(m) // expected-error {{use of undeclared identifier 'm'}}
#pragma omp allocate(ns::m)
#pragma omp allocate(ns \
: m) // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}}

const int h = 12;
const volatile int i = 10;
#pragma omp allocate(h, i)

template <class T>
class TempClass {
private:
T a;
TempClass() : a() {}

public:
TempClass(T aaa) : a(aaa) {}
static T s;
#pragma omp allocate(s)
};
#pragma omp allocate(s) // expected-error {{use of undeclared identifier 's'}}

static __thread int t;
#pragma omp allocate(t)

// Register "0" is currently an invalid register for global register variables.
// Use "esp" instead of "0".
// register int reg0 __asm__("0");
register int reg0 __asm__("esp");
#pragma omp allocate(reg0)

int o; // expected-note {{candidate found by name lookup is 'o'}}
#pragma omp allocate(o)
namespace {
int o; // expected-note {{candidate found by name lookup is '(anonymous namespace)::o'}}
#pragma omp allocate(o)
#pragma omp allocate(o)
} // namespace
#pragma omp allocate(o) // expected-error {{reference to 'o' is ambiguous}}
#pragma omp allocate(::o)

int main(int argc, char **argv) {

int x, y = argc;
static double d1;
static double d2;
static double d3; // expected-note {{'d3' defined here}}
static double d4;
static TestClass LocalClass(y);
#pragma omp allocate(LocalClass)

d.a = a;
d2++;
;
#pragma omp allocate(argc + y) // expected-error {{expected identifier}}
#pragma omp allocate(argc, y)
#pragma omp allocate(d2)
#pragma omp allocate(d1)
{
++a;
d2 = 0;
#pragma omp allocate(d3) // expected-error {{'#pragma omp allocate' must appear in the scope of the 'd3' variable declaration}}
}
#pragma omp allocate(d3)
label:
#pragma omp allocate(d4) // expected-error {{'#pragma omp allocate' cannot be an immediate substatement}}

#pragma omp allocate(a) // expected-error {{'#pragma omp allocate' must appear in the scope of the 'a' variable declaration}}
return (y);
#pragma omp allocate(d) // expected-error {{'#pragma omp allocate' must appear in the scope of the 'd' variable declaration}}
}
36 changes: 36 additions & 0 deletions clang/test/PCH/chain-openmp-allocate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// no PCH
// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -ast-print -include %s -include %s %s -o - | FileCheck %s
// with PCH
// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -ast-print -chain-include %s -chain-include %s %s -o - | FileCheck %s
// no PCH
// RUN: %clang_cc1 -fopenmp -ast-print -include %s -include %s %s -o - | FileCheck %s -check-prefix=CHECK-ALLOC-1
// RUN: %clang_cc1 -fopenmp -ast-print -include %s -include %s %s -o - | FileCheck %s -check-prefix=CHECK-ALLOC-2
// with PCH
// RUN: %clang_cc1 -fopenmp -ast-print -chain-include %s -chain-include %s %s -o - | FileCheck %s -check-prefix=CHECK-ALLOC-1
// RUN: %clang_cc1 -fopenmp -ast-print -chain-include %s -chain-include %s %s -o - | FileCheck %s -check-prefix=CHECK-ALLOC-2

#if !defined(PASS1)
#define PASS1

int a;
// CHECK: int a;

#elif !defined(PASS2)
#define PASS2

#pragma omp allocate(a)
// CHECK: #pragma omp allocate(a)

#else

// CHECK-LABEL: foo
// CHECK-ALLOC-LABEL: foo
int foo() {
return a;
// CHECK: return a;
// CHECK-ALLOC-1: return a;
}

// CHECK-ALLOC-2: return a;

#endif
1 change: 1 addition & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6233,6 +6233,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::CXXDeductionGuide:
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::OMPAllocate:
case Decl::OMPDeclareReduction:
case Decl::OMPDeclareMapper:
case Decl::OMPRequires:
Expand Down