llvm-project/clang/lib/Sema/SemaOpenMP.cpp

182 lines
7.0 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/DeclOpenMP.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.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;
}
};
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
SourceLocation Loc,
Scope *CurScope,
ArrayRef<DeclarationNameInfo> IdList) {
SmallVector<DeclRefExpr *, 5> Vars;
for (ArrayRef<DeclarationNameInfo>::iterator I = IdList.begin(),
E = IdList.end();
I != E; ++I) {
LookupResult Lookup(*this, *I, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, NULL, true);
if (Lookup.isAmbiguous())
continue;
VarDecl *VD;
if (!Lookup.isSingleResult()) {
VarDeclFilterCCC Validator(*this);
TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope,
0, Validator);
std::string CorrectedStr = Corrected.getAsString(getLangOpts());
std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
if (Lookup.empty()) {
if (Corrected.isResolved()) {
Diag(I->getLoc(), diag::err_undeclared_var_use_suggest)
<< I->getName() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
} else {
Diag(I->getLoc(), diag::err_undeclared_var_use)
<< I->getName();
}
} else {
Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
<< I->getName() << Corrected.isResolved() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
}
if (!Corrected.isResolved()) continue;
VD = Corrected.getCorrectionDeclAs<VarDecl>();
} else {
if (!(VD = Lookup.getAsSingle<VarDecl>())) {
Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
<< I->getName() << 0;
Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
continue;
}
}
// OpenMP [2.9.2, Syntax, C/C++]
// Variables must be file-scope, namespace-scope, or static block-scope.
if (!VD->hasGlobalStorage()) {
Diag(I->getLoc(), diag::err_omp_global_var_arg)
<< getOpenMPDirectiveName(OMPD_threadprivate)
<< !VD->isStaticLocal();
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
continue;
}
// 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(I->getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
continue;
}
// 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(I->getLoc(), diag::err_omp_var_used)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
continue;
}
QualType ExprType = VD->getType().getNonReferenceType();
DeclRefExpr *Var = cast<DeclRefExpr>(BuildDeclRefExpr(VD,
ExprType,
VK_RValue,
I->getLoc()).take());
Vars.push_back(Var);
}
if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) {
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
return DeclGroupPtrTy();
}
OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
SourceLocation Loc,
ArrayRef<DeclRefExpr *> VarList) {
SmallVector<DeclRefExpr *, 5> Vars;
for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(),
E = VarList.end();
I != E; ++I) {
VarDecl *VD = cast<VarDecl>((*I)->getDecl());
SourceLocation ILoc = (*I)->getLocation();
// 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_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();
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
continue;
}
// Check if threadspecified is set.
if (VD->isThreadSpecified()) {
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
continue;
}
Vars.push_back(*I);
}
return Vars.empty() ?
0 : OMPThreadPrivateDecl::Create(Context,
getCurLexicalContext(),
Loc, Vars);
}