1818#include " clang/Basic/TargetInfo.h"
1919#include " clang/Lex/Preprocessor.h"
2020#include " clang/Sema/Lookup.h"
21+ #include " clang/Sema/ParsedAttr.h"
2122#include " clang/Sema/ScopeInfo.h"
2223#include " clang/Sema/Sema.h"
2324#include " clang/Sema/SemaDiagnostic.h"
@@ -68,13 +69,28 @@ ExprResult SemaCUDA::ActOnExecConfigExpr(Scope *S, SourceLocation LLLLoc,
6869 /* IsExecConfig=*/ true );
6970}
7071
71- CUDAFunctionTarget SemaCUDA::IdentifyTarget (const ParsedAttributesView &Attrs) {
72+ namespace {
73+
74+ // This iterator adaptor enables sharing a IdentifyTarget implementation for
75+ // ParsedAttributesView and for vectors of AttributeCommonInfo::Kind.
76+ struct AttrKindIterator
77+ : llvm::iterator_adaptor_base<
78+ AttrKindIterator, ParsedAttributesView::const_iterator,
79+ std::random_access_iterator_tag, clang::AttributeCommonInfo::Kind> {
80+ AttrKindIterator () : iterator_adaptor_base(nullptr ) {}
81+ AttrKindIterator (ParsedAttributesView::const_iterator I)
82+ : iterator_adaptor_base(I) {}
83+ clang::AttributeCommonInfo::Kind operator *() const { return I->getKind (); }
84+ };
85+
86+ template <typename AKIterRange>
87+ CUDAFunctionTarget IdentifyTargetImpl (const AKIterRange &AttrKinds) {
7288 bool HasHostAttr = false ;
7389 bool HasDeviceAttr = false ;
7490 bool HasGlobalAttr = false ;
7591 bool HasInvalidTargetAttr = false ;
76- for (const ParsedAttr &AL : Attrs ) {
77- switch (AL. getKind () ) {
92+ for (const auto &AK : AttrKinds ) {
93+ switch (AK ) {
7894 case ParsedAttr::AT_CUDAGlobal:
7995 HasGlobalAttr = true ;
8096 break ;
@@ -107,6 +123,18 @@ CUDAFunctionTarget SemaCUDA::IdentifyTarget(const ParsedAttributesView &Attrs) {
107123 return CUDAFunctionTarget::Host;
108124}
109125
126+ } // namespace
127+
128+ CUDAFunctionTarget SemaCUDA::IdentifyTarget (const ParsedAttributesView &Attrs) {
129+ return IdentifyTargetImpl (make_range (AttrKindIterator (Attrs.begin ()),
130+ AttrKindIterator (Attrs.end ())));
131+ }
132+
133+ CUDAFunctionTarget SemaCUDA::IdentifyTarget (
134+ const SmallVectorImpl<clang::AttributeCommonInfo::Kind> &AttrKinds) {
135+ return IdentifyTargetImpl (AttrKinds);
136+ }
137+
110138template <typename A>
111139static bool hasAttr (const Decl *D, bool IgnoreImplicitAttr) {
112140 return D->hasAttrs () && llvm::any_of (D->getAttrs (), [&](Attr *Attribute) {
@@ -115,20 +143,65 @@ static bool hasAttr(const Decl *D, bool IgnoreImplicitAttr) {
115143 });
116144}
117145
146+ SemaCUDA::CUDATargetContext::CUDATargetContext (SemaCUDA *S,
147+ CUDATargetContextKind Kind,
148+ CUDAFunctionTarget Target)
149+ : Kind(Kind), S(S), Target(Target) {}
150+
151+ CUDAFunctionTarget SemaCUDA::CUDATargetContext::getTarget () {
152+ TargetQueried = true ;
153+ return Target;
154+ }
155+
156+ void SemaCUDA::CUDATargetContext::tryRegisterTargetAttrs (
157+ const ParsedAttributesView &Attrs) {
158+ if (Kind != CTCK_Declaration)
159+ return ;
160+ for (const auto &A : Attrs) {
161+ auto AK = A.getKind ();
162+ switch (AK) {
163+ case ParsedAttr::AT_CUDAGlobal:
164+ case ParsedAttr::AT_CUDAHost:
165+ case ParsedAttr::AT_CUDADevice:
166+ case ParsedAttr::AT_CUDAInvalidTarget:
167+ break ;
168+ default :
169+ continue ;
170+ }
171+ AttrKinds.push_back (AK);
172+ CUDAFunctionTarget NewTarget = S->IdentifyTarget (AttrKinds);
173+ if (TargetQueried && (NewTarget != Target))
174+ S->Diag (A.getLoc (), diag::warn_target_specfier_ignored);
175+ Target = NewTarget;
176+ }
177+ }
178+
118179SemaCUDA::CUDATargetContextRAII::CUDATargetContextRAII (
119180 SemaCUDA &S_, SemaCUDA::CUDATargetContextKind K, Decl *D)
120181 : S(S_) {
121182 SavedCtx = S.CurCUDATargetCtx ;
122- assert (K == SemaCUDA::CTCK_InitGlobalVar);
123- auto *VD = dyn_cast_or_null<VarDecl>(D);
124- if (VD && VD->hasGlobalStorage () && !VD->isStaticLocal ()) {
125- auto Target = CUDAFunctionTarget::Host;
126- if ((hasAttr<CUDADeviceAttr>(VD, /* IgnoreImplicit=*/ true ) &&
127- !hasAttr<CUDAHostAttr>(VD, /* IgnoreImplicit=*/ true )) ||
128- hasAttr<CUDASharedAttr>(VD, /* IgnoreImplicit=*/ true ) ||
129- hasAttr<CUDAConstantAttr>(VD, /* IgnoreImplicit=*/ true ))
130- Target = CUDAFunctionTarget::Device;
131- S.CurCUDATargetCtx = {Target, K, VD};
183+
184+ switch (K) {
185+ case SemaCUDA::CTCK_InitGlobalVar: {
186+ auto *VD = dyn_cast_or_null<VarDecl>(D);
187+ if (VD && VD->hasGlobalStorage () && !VD->isStaticLocal ()) {
188+ auto Target = CUDAFunctionTarget::Host;
189+ if ((hasAttr<CUDADeviceAttr>(VD, /* IgnoreImplicit=*/ true ) &&
190+ !hasAttr<CUDAHostAttr>(VD, /* IgnoreImplicit=*/ true )) ||
191+ hasAttr<CUDASharedAttr>(VD, /* IgnoreImplicit=*/ true ) ||
192+ hasAttr<CUDAConstantAttr>(VD, /* IgnoreImplicit=*/ true ))
193+ Target = CUDAFunctionTarget::Device;
194+ S.CurCUDATargetCtx = CUDATargetContext (&S, K, Target);
195+ }
196+ break ;
197+ }
198+ case SemaCUDA::CTCK_Declaration:
199+ // The target is updated once relevant attributes are parsed. Initialize
200+ // with the target used if no attributes are present: Host.
201+ S.CurCUDATargetCtx = CUDATargetContext (&S, K, CUDAFunctionTarget::Host);
202+ break ;
203+ default :
204+ llvm_unreachable (" unexpected context kind" );
132205 }
133206}
134207
@@ -137,7 +210,7 @@ CUDAFunctionTarget SemaCUDA::IdentifyTarget(const FunctionDecl *D,
137210 bool IgnoreImplicitHDAttr) {
138211 // Code that lives outside a function gets the target from CurCUDATargetCtx.
139212 if (D == nullptr )
140- return CurCUDATargetCtx.Target ;
213+ return CurCUDATargetCtx.getTarget () ;
141214
142215 if (D->hasAttr <CUDAInvalidTargetAttr>())
143216 return CUDAFunctionTarget::InvalidTarget;
@@ -232,7 +305,7 @@ SemaCUDA::IdentifyPreference(const FunctionDecl *Caller,
232305 // trivial ctor/dtor without device attr to be used. Non-trivial ctor/dtor
233306 // will be diagnosed by checkAllowedInitializer.
234307 if (Caller == nullptr && CurCUDATargetCtx.Kind == CTCK_InitGlobalVar &&
235- CurCUDATargetCtx.Target == CUDAFunctionTarget::Device &&
308+ CurCUDATargetCtx.getTarget () == CUDAFunctionTarget::Device &&
236309 (isa<CXXConstructorDecl>(Callee) || isa<CXXDestructorDecl>(Callee)))
237310 return CFP_HostDevice;
238311
@@ -297,8 +370,16 @@ SemaCUDA::IdentifyPreference(const FunctionDecl *Caller,
297370 (CallerTarget == CUDAFunctionTarget::Device &&
298371 CalleeTarget == CUDAFunctionTarget::Host) ||
299372 (CallerTarget == CUDAFunctionTarget::Global &&
300- CalleeTarget == CUDAFunctionTarget::Host))
373+ CalleeTarget == CUDAFunctionTarget::Host)) {
374+ // In declaration contexts outside of function bodies and variable
375+ // initializers, tolerate mismatched function targets as long as they are
376+ // not codegened.
377+ if (CurCUDATargetCtx.Kind == CTCK_Declaration &&
378+ !this ->SemaRef .getCurFunctionDecl (/* AllowLambda=*/ true ))
379+ return CFP_WrongSide;
380+
301381 return CFP_Never;
382+ }
302383
303384 llvm_unreachable (" All cases should've been handled by now." );
304385}
0 commit comments