Go to the documentation of this file.
25 #include "llvm/ADT/Optional.h"
26 #include "llvm/ADT/SmallVector.h"
27 using namespace clang;
32 if (
auto *A = D->
getAttr<AttrT>())
33 return !A->isImplicit();
38 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
39 ForceCUDAHostDeviceDepth++;
43 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
44 if (ForceCUDAHostDeviceDepth == 0)
46 ForceCUDAHostDeviceDepth--;
63 return BuildCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc,
nullptr,
69 bool HasHostAttr =
false;
70 bool HasDeviceAttr =
false;
71 bool HasGlobalAttr =
false;
72 bool HasInvalidTargetAttr =
false;
74 switch (AL.getKind()) {
75 case ParsedAttr::AT_CUDAGlobal:
78 case ParsedAttr::AT_CUDAHost:
81 case ParsedAttr::AT_CUDADevice:
84 case ParsedAttr::AT_CUDAInvalidTarget:
85 HasInvalidTargetAttr =
true;
92 if (HasInvalidTargetAttr)
98 if (HasHostAttr && HasDeviceAttr)
107 template <
typename A>
110 return isa<A>(Attribute) &&
111 !(IgnoreImplicitAttr && Attribute->isImplicit());
117 bool IgnoreImplicitHDAttr) {
122 if (D->
hasAttr<CUDAInvalidTargetAttr>())
125 if (D->
hasAttr<CUDAGlobalAttr>())
128 if (hasAttr<CUDADeviceAttr>(D, IgnoreImplicitHDAttr)) {
129 if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr))
132 }
else if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) {
135 !IgnoreImplicitHDAttr) {
146 if (Var->
hasAttr<HIPManagedAttr>())
152 Var->
hasAttr<CUDAConstantAttr>() &&
153 !hasExplicitAttr<CUDAConstantAttr>(Var))
155 if (Var->
hasAttr<CUDADeviceAttr>() || Var->
hasAttr<CUDAConstantAttr>() ||
156 Var->
hasAttr<CUDASharedAttr>() ||
209 assert(Callee &&
"Callee must be valid.");
229 if (CalleeTarget == CallerTarget ||
255 llvm_unreachable(
"All cases should've been handled by now.");
261 if (
auto *A = D->
getAttr<AttrT>())
262 return A->isImplicit();
267 bool IsImplicitDevAttr = hasImplicitAttr<CUDADeviceAttr>(D);
268 bool IsImplicitHostAttr = hasImplicitAttr<CUDAHostAttr>(D);
269 return IsImplicitDevAttr && IsImplicitHostAttr;
275 if (Matches.size() <= 1)
278 using Pair = std::pair<DeclAccessPair, FunctionDecl*>;
281 auto GetCFP = [&](
const Pair &Match) {
287 Matches.begin(), Matches.end(),
288 [&](
const Pair &M1,
const Pair &M2) { return GetCFP(M1) < GetCFP(M2); }));
291 llvm::erase_if(Matches,
292 [&](
const Pair &Match) {
return GetCFP(Match) < BestCFP; });
312 *ResolvedTarget = Target2;
314 *ResolvedTarget = Target1;
315 }
else if (Target1 != Target2) {
318 *ResolvedTarget = Target1;
333 bool HasH = MemberDecl->
hasAttr<CUDAHostAttr>();
334 bool HasD = MemberDecl->
hasAttr<CUDADeviceAttr>();
335 bool HasExplicitAttr =
336 (HasD && !MemberDecl->
getAttr<CUDADeviceAttr>()->isImplicit()) ||
337 (HasH && !MemberDecl->
getAttr<CUDAHostAttr>()->isImplicit());
338 if (!InClass || HasExplicitAttr)
351 for (
const auto &B : ClassDecl->
bases()) {
352 if (!B.isVirtual()) {
358 llvm::append_range(Bases, llvm::make_pointer_range(ClassDecl->
vbases()));
361 for (
const auto *B : Bases) {
380 if (!InferredTarget.hasValue()) {
381 InferredTarget = BaseMethodTarget;
384 InferredTarget.getValue(), BaseMethodTarget,
385 InferredTarget.getPointer());
386 if (ResolutionError) {
389 diag::note_implicit_member_target_infer_collision)
390 << (
unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
392 MemberDecl->
addAttr(CUDAInvalidTargetAttr::CreateImplicit(
Context));
399 for (
const auto *F : ClassDecl->
fields()) {
400 if (F->isInvalidDecl()) {
413 ConstRHS && !F->isMutable(),
424 if (!InferredTarget.hasValue()) {
425 InferredTarget = FieldMethodTarget;
428 InferredTarget.getValue(), FieldMethodTarget,
429 InferredTarget.getPointer());
430 if (ResolutionError) {
433 diag::note_implicit_member_target_infer_collision)
434 << (
unsigned)CSM << InferredTarget.getValue()
435 << FieldMethodTarget;
437 MemberDecl->
addAttr(CUDAInvalidTargetAttr::CreateImplicit(
Context));
446 bool NeedsH =
true, NeedsD =
true;
447 if (InferredTarget.hasValue()) {
450 else if (InferredTarget.getValue() ==
CFT_Host)
492 if (const CXXConstructExpr *CE =
493 dyn_cast<CXXConstructExpr>(CI->getInit()))
494 return isEmptyCudaConstructor(Loc, CE->getConstructor());
536 if (CXXRecordDecl *RD = BS.getType()->getAsCXXRecordDecl())
537 return isEmptyCudaDestructor(Loc, RD->getDestructor());
544 if (CXXRecordDecl *RD = Field->getType()
545 ->getBaseElementTypeUnsafe()
546 ->getAsCXXRecordDecl())
547 return isEmptyCudaDestructor(Loc, RD->getDestructor());
556 enum CUDAInitializerCheckKind {
557 CICK_DeviceOrConstant,
561 bool IsDependentVar(
VarDecl *VD) {
564 if (
const auto *Init = VD->
getInit())
565 return Init->isValueDependent();
578 bool HasAllowedCUDADeviceStaticInitializer(
Sema &S,
VarDecl *VD,
579 CUDAInitializerCheckKind CheckKind) {
581 assert(!IsDependentVar(VD) &&
"do not check dependent var");
583 auto IsEmptyInit = [&](
const Expr *Init) {
586 if (
const auto *CE = dyn_cast<CXXConstructExpr>(Init)) {
591 auto IsConstantInit = [&](
const Expr *Init) {
595 return Init->isConstantInitializer(S.
Context,
598 auto HasEmptyDtor = [&](
VarDecl *VD) {
603 if (CheckKind == CICK_Shared)
604 return IsEmptyInit(Init) && HasEmptyDtor(VD);
605 return S.
LangOpts.GPUAllowDeviceInit ||
606 ((IsEmptyInit(Init) || IsConstantInit(Init)) && HasEmptyDtor(VD));
617 bool IsSharedVar = VD->
hasAttr<CUDASharedAttr>();
618 bool IsDeviceOrConstantVar =
620 (VD->
hasAttr<CUDADeviceAttr>() || VD->
hasAttr<CUDAConstantAttr>());
621 if (IsDeviceOrConstantVar || IsSharedVar) {
622 if (HasAllowedCUDADeviceStaticInitializer(
623 *
this, VD, IsSharedVar ? CICK_Shared : CICK_DeviceOrConstant))
626 IsSharedVar ? diag::err_shared_var_init : diag::err_dynamic_var_init)
627 << Init->getSourceRange();
634 InitFn = CE->getConstructor();
635 }
else if (
const CallExpr *CE = dyn_cast<CallExpr>(Init)) {
636 InitFn = CE->getDirectCallee();
642 << InitFnTarget << InitFn;
643 Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn;
664 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
666 if (ForceCUDAHostDeviceDepth > 0) {
667 if (!NewD->
hasAttr<CUDAHostAttr>())
669 if (!NewD->
hasAttr<CUDADeviceAttr>())
676 NewD->
hasAttr<CUDADeviceAttr>() || NewD->
hasAttr<CUDAGlobalAttr>())
681 auto IsMatchingDeviceFn = [&](
NamedDecl *D) {
683 D = Using->getTargetDecl();
685 return OldD && OldD->
hasAttr<CUDADeviceAttr>() &&
686 !OldD->
hasAttr<CUDAHostAttr>() &&
690 auto It = llvm::find_if(
Previous, IsMatchingDeviceFn);
699 diag::err_cuda_unattributed_constexpr_cannot_overload_device)
702 diag::note_cuda_conflicting_device_function_declared_here);
718 !VD->
hasAttr<CUDAConstantAttr>() && !VD->
hasAttr<CUDASharedAttr>() &&
720 !IsDependentVar(VD) &&
722 HasAllowedCUDADeviceStaticInitializer(*
this, VD,
723 CICK_DeviceOrConstant))) {
730 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
760 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
788 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
789 assert(Callee &&
"Callee may not be null.");
792 if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated())
803 bool CallerKnownEmitted =
806 CallerKnownEmitted] {
810 assert(Caller &&
"Never/wrongSide calls require a non-null caller");
814 return CallerKnownEmitted
825 Callee->hasAttr<CUDAGlobalAttr>() && !Callee->isDefined())
840 if (!Callee->getBuiltinID())
842 diag::note_previous_decl, Caller, *
this)
876 bool CalleeIsDevice = Callee->hasAttr<CUDADeviceAttr>();
878 !Caller->
hasAttr<CUDAGlobalAttr>() && !Caller->
hasAttr<CUDADeviceAttr>();
879 bool ShouldCheck = CalleeIsDevice && CallerIsHost;
885 diag::err_capture_bad_target, Callee, *
this)
893 diag::warn_maybe_capture_bad_target_this_ptr, Callee,
899 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
900 if (Method->
hasAttr<CUDAHostAttr>() || Method->
hasAttr<CUDADeviceAttr>())
908 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
921 if (NewTarget != OldTarget &&
927 << NewTarget << NewFD->
getDeclName() << OldTarget << OldFD;
928 Diag(OldFD->getLocation(), diag::note_previous_declaration);
935 template <
typename AttrTy>
938 if (AttrTy *Attribute = TemplateFD.
getAttr<AttrTy>()) {
939 AttrTy *Clone = Attribute->clone(S.
Context);
940 Clone->setInherited(
true);
948 copyAttrIfPresent<CUDAGlobalAttr>(*
this, FD, TemplateFD);
949 copyAttrIfPresent<CUDAHostAttr>(*
this, FD, TemplateFD);
950 copyAttrIfPresent<CUDADeviceAttr>(*
this, FD, TemplateFD);
955 return getLangOpts().HIPUseNewLaunchAPI ?
"__hipPushCallConfiguration"
956 :
"hipConfigureCall";
961 return "__cudaPushCallConfiguration";
964 return "cudaConfigureCall";
SpecialMemberOverloadResult - The overloading result for a special member function.
bool isThisCapture() const
SourceLocation getLocation() const
Retrieve the location at which this variable was captured.
static bool hasAttr(const FunctionDecl *D, bool IgnoreImplicitAttr)
Represents a C++ constructor within a class.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
bool isFileVarDecl() const
Returns true for file scoped variable declaration.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
ASTContext & getASTContext() const
bool isConstQualified() const
Determine whether this type is const-qualified.
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
void checkCUDATargetOverload(FunctionDecl *NewFD, const LookupResult &Previous)
Check whether NewFD is a valid overload for CUDA.
static bool hasImplicitAttr(const FunctionDecl *D)
VarDecl * getVariable() const
void PushForceCUDAHostDevice()
Increments our count of the number of times we've seen a pragma forcing functions to be host device.
Encodes a location in the source.
bool isReferenceCapture() const
This represents a decl that may have a name.
A (possibly-)qualified type.
Represents a member of a struct/union/class.
Represents the results of name lookup.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
const llvm::VersionTuple & getSDKVersion() const
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
decl_type * getFirstDecl()
Return the first declaration of this declaration or itself if this is the only declaration.
void CUDACheckLambdaCapture(CXXMethodDecl *D, const sema::Capture &Capture)
@ CVT_Unified
Emitted on both sides with different addresses.
Represents a shadow declaration implicitly introduced into a scope by a (resolved) using-declaration ...
SourceManager & getSourceManager() const
bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD)
bool isUserProvided() const
True if this method is user-declared and was not deleted or defaulted on its first declaration.
ExprResult BuildCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig=nullptr, bool IsExecConfig=false, bool AllowRecovery=false)
BuildCallExpr - Handle a call to Fn with the specified array of arguments.
bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, bool ConsiderCudaAttrs=true, bool ConsiderRequiresClauses=true)
DeclContext * getLexicalParent()
getLexicalParent - Returns the containing lexical DeclContext.
SmallVector< ExpressionEvaluationContextRecord, 8 > ExprEvalContexts
A stack of expression evaluation contexts.
FunctionDecl * getcudaConfigureCallDecl()
bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXSpecialMember CSM, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose)
Given a implicit special member, infer its CUDA target from the calls it needs to make to underlying ...
SemaDiagnosticBuilder CUDADiagIfDeviceCode(SourceLocation Loc, unsigned DiagID)
Creates a SemaDiagnosticBuilder that emits the diagnostic if the current context is "used as device c...
const LangOptions & getLangOpts() const
bool isCUDADeviceBuiltinTextureType() const
Check if the type is the CUDA device builtin texture type.
FunctionDecl * getCurFunctionDecl(bool AllowLambda=false)
Returns a pointer to the innermost enclosing function, or nullptr if the current context is not insid...
Declaration of a template function.
bool isReferenceType() const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
void MaybeAddCUDAConstantAttr(VarDecl *VD)
May add implicit CUDAConstantAttr attribute to VD, depending on VD and current compilation settings.
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc)
Scope - A scope is a transient data structure that is used while parsing the program.
@ K_Nop
Emit no diagnostics.
@ K_Immediate
Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
bool isStaticDataMember() const
Determines whether this is a static data member.
bool hasTrivialBody() const
Returns whether the function has a trivial body that does not require any specific codegen.
static bool resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, Sema::CUDAFunctionTarget Target2, Sema::CUDAFunctionTarget *ResolvedTarget)
When an implicitly-declared special member has to invoke more than one base/field special member,...
const T * getAs() const
Member-template getAs<specific type>'.
bool isInvalidDecl() const
DiagnosticsEngine & Diags
bool CudaFeatureEnabled(llvm::VersionTuple, CudaFeature)
const IntrusiveRefCntPtr< DiagnosticIDs > & getDiagnosticIDs() const
Represents a C++ destructor within a class.
void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD, const LookupResult &Previous)
May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, depending on FD and the current co...
ParsedAttr - Represents a syntactic attribute.
bool IsLastErrorImmediate
Is the last error level diagnostic immediate.
Represents a variable declaration or definition.
static bool isCUDAImplicitHostDeviceFunction(const FunctionDecl *D)
CXXMethodDecl * getMethod() const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
SemaDiagnosticBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID)
Creates a SemaDiagnosticBuilder that emits the diagnostic if the current context is "used as host cod...
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive=false, bool DefinitionRequired=false, bool AtEndOfTU=false)
Instantiate the definition of the given function from its template.
base_class_range vbases()
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
const LangOptions & LangOpts
@ K_Deferred
Create a deferred diagnostic, which is emitted only if the function it's attached to is codegen'ed.
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
llvm::DenseSet< FunctionDeclAndLoc > LocsWithCUDACallDiags
FunctionDecls and SourceLocations for which CheckCUDACall has emitted a (maybe deferred) "bad call" d...
@ CVT_Both
Emitted on host side only.
Represents a C++ struct/union/class.
bool PopForceCUDAHostDevice()
Decrements our count of the number of times we've seen a pragma forcing functions to be host device.
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
void CUDASetLambdaAttrs(CXXMethodDecl *Method)
Set device or host device attributes on the given lambda operator() method.
field_range fields() const
static bool hasExplicitAttr(const VarDecl *D)
bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD)
@ K_ImmediateWithCallStack
Emit the diagnostic immediately, and, if it's a warning or error, also emit a call stack showing how ...
Sema - This implements semantic analysis and AST building for C.
static void copyAttrIfPresent(Sema &S, FunctionDecl *FD, const FunctionDecl &TemplateFD)
const Expr * getInit() const
const TargetInfo & getTargetInfo() const
llvm::DenseSet< const ValueDecl * > CUDAExternalDeviceDeclODRUsedByHost
Keep track of CUDA/HIP external kernels or device variables ODR-used by host code.
A generic diagnostic builder for errors which may or may not be deferred.
FunctionDecl * getTemplatedDecl() const
Get the underlying function declaration of the template.
FunctionEmissionStatus getEmissionStatus(FunctionDecl *Decl, bool Final=false)
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee)
Identifies relative preference of a given Caller/Callee combination, based on their host/device attri...
void EraseUnwantedCUDAMatches(const FunctionDecl *Caller, SmallVectorImpl< std::pair< DeclAccessPair, FunctionDecl * >> &Matches)
Finds a function in Matches with highest calling priority from Caller context and erases all function...
Represents a base class of a C++ class.
Attr - This represents one attribute.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
bool isAbstract() const
Determine whether this class has a pure virtual function.
bool isVariadic() const
Whether this function is variadic.
CUDAFunctionTarget CurrentCUDATarget()
Gets the CUDA target for the current context.
std::string getCudaConfigureFuncName() const
Returns the name of the launch configuration function.
bool isDynamicClass() const
RecordDecl * getDecl() const
SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis)
void inheritCUDATargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD)
Copies target attributes from the template TD to the function FD.
CXXSpecialMember
Kinds of C++ special members.
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
@ CVT_Host
Emitted on device side with a shadow variable on host side.
This represents one expression.
bool isVariableCapture() const
Represents a C++ base or member initializer.
void checkAllowedCUDAInitializer(VarDecl *VD)
void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse=true)
Mark a function referenced, and check whether it is odr-used (C++ [basic.def.odr]p2,...
SourceLocation getLocation() const
A reference to a declared variable, function, enum, etc.
Represents a function declaration or definition.
bool isCUDADeviceBuiltinSurfaceType() const
Check if the type is the CUDA device builtin surface type.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Represents a call to a C++ constructor.
bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const
Returns true if the function has a definition that does not need to be instantiated.
CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, bool IgnoreImplicitHDAttr=false)
Determines whether the given function is a CUDA device/host/kernel/etc.
bool CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee)
Check whether we're allowed to call Callee from the current context.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a static or instance method of a struct/union/class.
DeclContext * getDeclContext()