forked from OSchip/llvm-project
407 lines
15 KiB
C++
407 lines
15 KiB
C++
//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ----------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
/// \brief This file implements semantic analysis for OpenMP directives and
|
|
/// clauses.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Basic/OpenMPKinds.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
#include "clang/AST/DeclOpenMP.h"
|
|
#include "clang/AST/StmtCXX.h"
|
|
#include "clang/AST/StmtOpenMP.h"
|
|
#include "clang/AST/StmtVisitor.h"
|
|
#include "clang/Lex/Preprocessor.h"
|
|
#include "clang/Sema/Initialization.h"
|
|
#include "clang/Sema/SemaInternal.h"
|
|
#include "clang/Sema/Lookup.h"
|
|
#include "clang/Sema/Scope.h"
|
|
#include "clang/Sema/ScopeInfo.h"
|
|
using namespace clang;
|
|
|
|
namespace {
|
|
|
|
class VarDeclFilterCCC : public CorrectionCandidateCallback {
|
|
private:
|
|
Sema &Actions;
|
|
public:
|
|
VarDeclFilterCCC(Sema &S) : Actions(S) { }
|
|
virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
|
|
NamedDecl *ND = Candidate.getCorrectionDecl();
|
|
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {
|
|
return VD->hasGlobalStorage() &&
|
|
Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
|
|
Actions.getCurScope());
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
|
|
ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
|
|
CXXScopeSpec &ScopeSpec,
|
|
const DeclarationNameInfo &Id) {
|
|
LookupResult Lookup(*this, Id, LookupOrdinaryName);
|
|
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
|
|
|
|
if (Lookup.isAmbiguous())
|
|
return ExprError();
|
|
|
|
VarDecl *VD;
|
|
if (!Lookup.isSingleResult()) {
|
|
VarDeclFilterCCC Validator(*this);
|
|
if (TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
|
|
0, Validator)) {
|
|
diagnoseTypo(Corrected,
|
|
PDiag(Lookup.empty()? diag::err_undeclared_var_use_suggest
|
|
: diag::err_omp_expected_var_arg_suggest)
|
|
<< Id.getName());
|
|
VD = Corrected.getCorrectionDeclAs<VarDecl>();
|
|
} else {
|
|
Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use
|
|
: diag::err_omp_expected_var_arg)
|
|
<< Id.getName();
|
|
return ExprError();
|
|
}
|
|
} else {
|
|
if (!(VD = Lookup.getAsSingle<VarDecl>())) {
|
|
Diag(Id.getLoc(), diag::err_omp_expected_var_arg)
|
|
<< Id.getName();
|
|
Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
|
|
return ExprError();
|
|
}
|
|
}
|
|
Lookup.suppressDiagnostics();
|
|
|
|
// OpenMP [2.9.2, Syntax, C/C++]
|
|
// Variables must be file-scope, namespace-scope, or static block-scope.
|
|
if (!VD->hasGlobalStorage()) {
|
|
Diag(Id.getLoc(), diag::err_omp_global_var_arg)
|
|
<< getOpenMPDirectiveName(OMPD_threadprivate)
|
|
<< !VD->isStaticLocal();
|
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
VarDecl::DeclarationOnly;
|
|
Diag(VD->getLocation(),
|
|
IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD;
|
|
return ExprError();
|
|
}
|
|
|
|
// OpenMP [2.9.2, Restrictions, C/C++, p.2]
|
|
// A threadprivate directive for file-scope variables must appear outside
|
|
// any definition or declaration.
|
|
// OpenMP [2.9.2, Restrictions, C/C++, p.3]
|
|
// A threadprivate directive for static class member variables must appear
|
|
// in the class definition, in the same scope in which the member
|
|
// variables are declared.
|
|
// OpenMP [2.9.2, Restrictions, C/C++, p.4]
|
|
// A threadprivate directive for namespace-scope variables must appear
|
|
// outside any definition or declaration other than the namespace
|
|
// definition itself.
|
|
// 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.
|
|
NamedDecl *ND = cast<NamedDecl>(VD);
|
|
if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
|
|
Diag(Id.getLoc(), diag::err_omp_var_scope)
|
|
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
|
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
VarDecl::DeclarationOnly;
|
|
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
|
|
diag::note_defined_here) << VD;
|
|
return ExprError();
|
|
}
|
|
|
|
// 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()) {
|
|
Diag(Id.getLoc(), diag::err_omp_var_used)
|
|
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
|
|
return ExprError();
|
|
}
|
|
|
|
QualType ExprType = VD->getType().getNonReferenceType();
|
|
ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc());
|
|
return DE;
|
|
}
|
|
|
|
Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
|
|
SourceLocation Loc,
|
|
ArrayRef<Expr *> VarList) {
|
|
if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {
|
|
CurContext->addDecl(D);
|
|
return DeclGroupPtrTy::make(DeclGroupRef(D));
|
|
}
|
|
return DeclGroupPtrTy();
|
|
}
|
|
|
|
OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
|
|
SourceLocation Loc,
|
|
ArrayRef<Expr *> VarList) {
|
|
SmallVector<Expr *, 8> Vars;
|
|
for (ArrayRef<Expr *>::iterator I = VarList.begin(),
|
|
E = VarList.end();
|
|
I != E; ++I) {
|
|
DeclRefExpr *DE = cast<DeclRefExpr>(*I);
|
|
VarDecl *VD = cast<VarDecl>(DE->getDecl());
|
|
SourceLocation ILoc = DE->getExprLoc();
|
|
|
|
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
|
|
// A threadprivate variable must not have an incomplete type.
|
|
if (RequireCompleteType(ILoc, VD->getType(),
|
|
diag::err_omp_threadprivate_incomplete_type)) {
|
|
continue;
|
|
}
|
|
|
|
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
|
|
// A threadprivate variable must not have a reference type.
|
|
if (VD->getType()->isReferenceType()) {
|
|
Diag(ILoc, diag::err_omp_ref_type_arg)
|
|
<< getOpenMPDirectiveName(OMPD_threadprivate)
|
|
<< VD->getType();
|
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
VarDecl::DeclarationOnly;
|
|
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
|
|
diag::note_defined_here) << VD;
|
|
continue;
|
|
}
|
|
|
|
// Check if this is a TLS variable.
|
|
if (VD->getTLSKind()) {
|
|
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
|
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
VarDecl::DeclarationOnly;
|
|
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
|
|
diag::note_defined_here) << VD;
|
|
continue;
|
|
}
|
|
|
|
Vars.push_back(*I);
|
|
}
|
|
return Vars.empty() ?
|
|
0 : OMPThreadPrivateDecl::Create(Context,
|
|
getCurLexicalContext(),
|
|
Loc, Vars);
|
|
}
|
|
|
|
StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
|
|
ArrayRef<OMPClause *> Clauses,
|
|
Stmt *AStmt,
|
|
SourceLocation StartLoc,
|
|
SourceLocation EndLoc) {
|
|
StmtResult Res = StmtError();
|
|
switch (Kind) {
|
|
case OMPD_parallel:
|
|
Res = ActOnOpenMPParallelDirective(Clauses, AStmt, StartLoc, EndLoc);
|
|
break;
|
|
case OMPD_threadprivate:
|
|
case OMPD_task:
|
|
llvm_unreachable("OpenMP Directive is not allowed");
|
|
case OMPD_unknown:
|
|
case NUM_OPENMP_DIRECTIVES:
|
|
llvm_unreachable("Unknown OpenMP directive");
|
|
}
|
|
return Res;
|
|
}
|
|
|
|
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
|
|
Stmt *AStmt,
|
|
SourceLocation StartLoc,
|
|
SourceLocation EndLoc) {
|
|
getCurFunction()->setHasBranchProtectedScope();
|
|
|
|
return Owned(OMPParallelDirective::Create(Context, StartLoc, EndLoc,
|
|
Clauses, AStmt));
|
|
}
|
|
|
|
OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
|
|
unsigned Argument,
|
|
SourceLocation ArgumentLoc,
|
|
SourceLocation StartLoc,
|
|
SourceLocation LParenLoc,
|
|
SourceLocation EndLoc) {
|
|
OMPClause *Res = 0;
|
|
switch (Kind) {
|
|
case OMPC_default:
|
|
Res = ActOnOpenMPDefaultClause(
|
|
static_cast<OpenMPDefaultClauseKind>(Argument),
|
|
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
|
|
break;
|
|
case OMPC_private:
|
|
case OMPC_threadprivate:
|
|
case OMPC_unknown:
|
|
case NUM_OPENMP_CLAUSES:
|
|
llvm_unreachable("Clause is not allowed.");
|
|
}
|
|
return Res;
|
|
}
|
|
|
|
OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
|
|
SourceLocation KindKwLoc,
|
|
SourceLocation StartLoc,
|
|
SourceLocation LParenLoc,
|
|
SourceLocation EndLoc) {
|
|
if (Kind == OMPC_DEFAULT_unknown) {
|
|
std::string Values;
|
|
std::string Sep(NUM_OPENMP_DEFAULT_KINDS > 1 ? ", " : "");
|
|
for (unsigned i = OMPC_DEFAULT_unknown + 1;
|
|
i < NUM_OPENMP_DEFAULT_KINDS; ++i) {
|
|
Values += "'";
|
|
Values += getOpenMPSimpleClauseTypeName(OMPC_default, i);
|
|
Values += "'";
|
|
switch (i) {
|
|
case NUM_OPENMP_DEFAULT_KINDS - 2:
|
|
Values += " or ";
|
|
break;
|
|
case NUM_OPENMP_DEFAULT_KINDS - 1:
|
|
break;
|
|
default:
|
|
Values += Sep;
|
|
break;
|
|
}
|
|
}
|
|
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
|
|
<< Values << getOpenMPClauseName(OMPC_default);
|
|
return 0;
|
|
}
|
|
return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc,
|
|
EndLoc);
|
|
}
|
|
|
|
OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
|
|
ArrayRef<Expr *> VarList,
|
|
SourceLocation StartLoc,
|
|
SourceLocation LParenLoc,
|
|
SourceLocation EndLoc) {
|
|
OMPClause *Res = 0;
|
|
switch (Kind) {
|
|
case OMPC_private:
|
|
Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
|
|
break;
|
|
case OMPC_default:
|
|
case OMPC_threadprivate:
|
|
case OMPC_unknown:
|
|
case NUM_OPENMP_CLAUSES:
|
|
llvm_unreachable("Clause is not allowed.");
|
|
}
|
|
return Res;
|
|
}
|
|
|
|
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
|
|
SourceLocation StartLoc,
|
|
SourceLocation LParenLoc,
|
|
SourceLocation EndLoc) {
|
|
SmallVector<Expr *, 8> Vars;
|
|
for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
|
|
I != E; ++I) {
|
|
if (*I && isa<DependentScopeDeclRefExpr>(*I)) {
|
|
// It will be analyzed later.
|
|
Vars.push_back(*I);
|
|
continue;
|
|
}
|
|
|
|
SourceLocation ELoc = (*I)->getExprLoc();
|
|
// OpenMP [2.1, C/C++]
|
|
// A list item is a variable name.
|
|
// OpenMP [2.9.3.3, Restrictions, p.1]
|
|
// A variable that is part of another variable (as an array or
|
|
// structure element) cannot appear in a private clause.
|
|
DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I);
|
|
if (!DE || !isa<VarDecl>(DE->getDecl())) {
|
|
Diag(ELoc, diag::err_omp_expected_var_name)
|
|
<< (*I)->getSourceRange();
|
|
continue;
|
|
}
|
|
Decl *D = DE->getDecl();
|
|
VarDecl *VD = cast<VarDecl>(D);
|
|
|
|
QualType Type = VD->getType();
|
|
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
|
|
// It will be analyzed later.
|
|
Vars.push_back(DE);
|
|
continue;
|
|
}
|
|
|
|
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
|
|
// A variable that appears in a private clause must not have an incomplete
|
|
// type or a reference type.
|
|
if (RequireCompleteType(ELoc, Type,
|
|
diag::err_omp_private_incomplete_type)) {
|
|
continue;
|
|
}
|
|
if (Type->isReferenceType()) {
|
|
Diag(ELoc, diag::err_omp_clause_ref_type_arg)
|
|
<< getOpenMPClauseName(OMPC_private) << Type;
|
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
VarDecl::DeclarationOnly;
|
|
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
|
|
diag::note_defined_here) << VD;
|
|
continue;
|
|
}
|
|
|
|
// OpenMP [2.9.3.3, Restrictions, C/C++, p.1]
|
|
// A variable of class type (or array thereof) that appears in a private
|
|
// clause requires an accesible, unambiguous default constructor for the
|
|
// class type.
|
|
while (Type.getNonReferenceType()->isArrayType()) {
|
|
Type = cast<ArrayType>(
|
|
Type.getNonReferenceType().getTypePtr())->getElementType();
|
|
}
|
|
CXXRecordDecl *RD = getLangOpts().CPlusPlus ?
|
|
Type.getNonReferenceType()->getAsCXXRecordDecl() : 0;
|
|
if (RD) {
|
|
CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
|
|
PartialDiagnostic PD =
|
|
PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
|
|
if (!CD ||
|
|
CheckConstructorAccess(ELoc, CD,
|
|
InitializedEntity::InitializeTemporary(Type),
|
|
CD->getAccess(), PD) == AR_inaccessible ||
|
|
CD->isDeleted()) {
|
|
Diag(ELoc, diag::err_omp_required_method)
|
|
<< getOpenMPClauseName(OMPC_private) << 0;
|
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
VarDecl::DeclarationOnly;
|
|
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
|
|
diag::note_defined_here) << VD;
|
|
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
|
|
continue;
|
|
}
|
|
MarkFunctionReferenced(ELoc, CD);
|
|
DiagnoseUseOfDecl(CD, ELoc);
|
|
|
|
CXXDestructorDecl *DD = RD->getDestructor();
|
|
if (DD) {
|
|
if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
|
|
DD->isDeleted()) {
|
|
Diag(ELoc, diag::err_omp_required_method)
|
|
<< getOpenMPClauseName(OMPC_private) << 4;
|
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
VarDecl::DeclarationOnly;
|
|
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
|
|
diag::note_defined_here) << VD;
|
|
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
|
|
continue;
|
|
}
|
|
MarkFunctionReferenced(ELoc, DD);
|
|
DiagnoseUseOfDecl(DD, ELoc);
|
|
}
|
|
}
|
|
|
|
Vars.push_back(DE);
|
|
}
|
|
|
|
if (Vars.empty()) return 0;
|
|
|
|
return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
|
|
}
|
|
|