//===--- 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);
TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
0, Validator);
std::string CorrectedStr = Corrected.getAsString(getLangOpts());
std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
if (Lookup.empty()) {
if (Corrected.isResolved()) {
Diag(Id.getLoc(), diag::err_undeclared_var_use_suggest)
<< Id.getName() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr);
} else {
Diag(Id.getLoc(), diag::err_undeclared_var_use)
<< Id.getName();
}
} else {
Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest)
<< Id.getName() << Corrected.isResolved() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr);
}
if (!Corrected.isResolved()) return ExprError();
VD = Corrected.getCorrectionDeclAs<VarDecl>();
} else {
if (!(VD = Lookup.getAsSingle<VarDecl>())) {
Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest)
<< Id.getName() << 0;
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);
}