23 #include "llvm/ADT/Optional.h"
24 #include "llvm/ADT/SmallVector.h"
25 using namespace clang;
28 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
29 ForceCUDAHostDeviceDepth++;
33 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
34 if (ForceCUDAHostDeviceDepth == 0)
36 ForceCUDAHostDeviceDepth--;
46 <<
"cudaConfigureCall");
53 return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc,
nullptr,
58 bool HasHostAttr =
false;
59 bool HasDeviceAttr =
false;
60 bool HasGlobalAttr =
false;
61 bool HasInvalidTargetAttr =
false;
64 case AttributeList::AT_CUDAGlobal:
67 case AttributeList::AT_CUDAHost:
70 case AttributeList::AT_CUDADevice:
73 case AttributeList::AT_CUDAInvalidTarget:
74 HasInvalidTargetAttr =
true;
81 if (HasInvalidTargetAttr)
87 if (HasHostAttr && HasDeviceAttr)
99 return isa<A>(Attribute) &&
100 !(IgnoreImplicitAttr && Attribute->isImplicit());
106 bool IgnoreImplicitHDAttr) {
111 if (D->
hasAttr<CUDAInvalidTargetAttr>())
114 if (D->
hasAttr<CUDAGlobalAttr>())
117 if (hasAttr<CUDADeviceAttr>(D, IgnoreImplicitHDAttr)) {
118 if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr))
121 }
else if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) {
123 }
else if (D->
isImplicit() && !IgnoreImplicitHDAttr) {
163 assert(Callee &&
"Callee must be valid.");
183 if (CalleeTarget == CallerTarget ||
209 llvm_unreachable(
"All cases should've been handled by now.");
218 using Pair = std::pair<DeclAccessPair, FunctionDecl*>;
221 auto GetCFP = [&](
const Pair &Match) {
228 [&](
const Pair &M1,
const Pair &M2) {
return GetCFP(M1) < GetCFP(M2); }));
232 [&](
const Pair &Match) {
return GetCFP(Match) < BestCFP; });
252 *ResolvedTarget = Target2;
254 *ResolvedTarget = Target1;
255 }
else if (Target1 != Target2) {
258 *ResolvedTarget = Target1;
279 for (
const auto &B : ClassDecl->
bases()) {
280 if (!B.isVirtual()) {
286 for (
const auto &VB : ClassDecl->
vbases()) {
287 Bases.push_back(&VB);
291 for (
const auto *B : Bases) {
306 if (!SMOR.getMethod())
310 if (!InferredTarget.hasValue()) {
311 InferredTarget = BaseMethodTarget;
314 InferredTarget.getValue(), BaseMethodTarget,
315 InferredTarget.getPointer());
316 if (ResolutionError) {
319 diag::note_implicit_member_target_infer_collision)
320 << (
unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
322 MemberDecl->
addAttr(CUDAInvalidTargetAttr::CreateImplicit(
Context));
329 for (
const auto *F : ClassDecl->
fields()) {
330 if (F->isInvalidDecl()) {
343 ConstRHS && !F->isMutable(),
349 if (!SMOR.getMethod())
354 if (!InferredTarget.hasValue()) {
355 InferredTarget = FieldMethodTarget;
358 InferredTarget.getValue(), FieldMethodTarget,
359 InferredTarget.getPointer());
360 if (ResolutionError) {
363 diag::note_implicit_member_target_infer_collision)
364 << (
unsigned)CSM << InferredTarget.getValue()
365 << FieldMethodTarget;
367 MemberDecl->
addAttr(CUDAInvalidTargetAttr::CreateImplicit(
Context));
373 if (InferredTarget.hasValue()) {
374 if (InferredTarget.getValue() ==
CFT_Device) {
376 }
else if (InferredTarget.getValue() ==
CFT_Host) {
417 dyn_cast<CXXConstructExpr>(CI->getInit()))
464 ->getBaseElementTypeUnsafe()
465 ->getAsCXXRecordDecl())
488 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
490 if (ForceCUDAHostDeviceDepth > 0) {
491 if (!NewD->
hasAttr<CUDAHostAttr>())
493 if (!NewD->
hasAttr<CUDADeviceAttr>())
500 NewD->
hasAttr<CUDADeviceAttr>() || NewD->
hasAttr<CUDAGlobalAttr>())
505 auto IsMatchingDeviceFn = [&](
NamedDecl *D) {
507 D = Using->getTargetDecl();
509 return OldD && OldD->
hasAttr<CUDADeviceAttr>() &&
510 !OldD->
hasAttr<CUDAHostAttr>() &&
514 auto It = llvm::find_if(Previous, IsMatchingDeviceFn);
515 if (It != Previous.
end()) {
523 diag::err_cuda_unattributed_constexpr_cannot_overload_device)
526 diag::note_cuda_conflicting_device_function_declared_here);
562 : S(S), Loc(Loc), DiagID(DiagID), Fn(Fn),
563 ShowCallStack(K == K_ImmediateWithCallStack || K == K_Deferred) {
569 ImmediateDiag.emplace(S.
Diag(Loc, DiagID));
572 assert(Fn &&
"Must have a function to attach the deferred diag to.");
573 PartialDiag.emplace(S.
PDiag(DiagID));
584 S.
Diags.
Report(FnIt->second.Loc, diag::note_called_by));
598 ImmediateDiag.reset();
599 if (IsWarningOrError && ShowCallStack)
601 }
else if (PartialDiag) {
602 assert(ShowCallStack &&
"Must always show call stack for deferred diags.");
643 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
670 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
699 bool HasWarningOrError =
false;
714 if (HasWarningOrError)
738 llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen;
739 Seen.insert(OrigCallee);
740 while (!Worklist.empty()) {
741 CallInfo C = Worklist.pop_back_val();
743 "Worklist should not contain known-emitted functions.");
750 if (
auto *Templ = C.Callee->getPrimaryTemplate()) {
753 Seen.insert(TemplFD);
755 { C.Caller, TemplFD, C.Loc});
770 Seen.insert(NewCallee);
772 { C.Callee, NewCallee, CallLoc});
782 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
783 assert(Callee &&
"Callee may not be null.");
793 if (CallerKnownEmitted)
811 assert(Caller &&
"WrongSide calls require a non-null caller");
832 CUDADiagBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *
this)
834 CUDADiagBuilder(DiagKind, Callee->getLocation(), diag::note_previous_decl,
842 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
843 if (Method->
hasAttr<CUDAHostAttr>() || Method->
hasAttr<CUDADeviceAttr>())
859 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
872 if (NewTarget != OldTarget &&
878 << NewTarget << NewFD->
getDeclName() << OldTarget << OldFD;
879 Diag(OldFD->getLocation(), diag::note_previous_declaration);
886 template <
typename AttrTy>
889 if (AttrTy *Attribute = TemplateFD.
getAttr<AttrTy>()) {
890 AttrTy *Clone = Attribute->clone(S.
Context);
891 Clone->setInherited(
true);
899 copyAttrIfPresent<CUDAGlobalAttr>(*
this, FD, TemplateFD);
900 copyAttrIfPresent<CUDAHostAttr>(*
this, FD, TemplateFD);
901 copyAttrIfPresent<CUDADeviceAttr>(*
this, FD, TemplateFD);
Defines the clang::ASTContext interface.
FunctionDecl * getDefinition()
Get the definition for this declaration.
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
StringRef getName() const
getName - Get the name of identifier for this declaration as a StringRef.
llvm::DenseMap< CanonicalDeclPtr< FunctionDecl >, llvm::MapVector< CanonicalDeclPtr< FunctionDecl >, SourceLocation > > CUDACallGraph
A partial call graph maintained during CUDA compilation to support deferred diagnostics.
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const
A (possibly-)qualified type.
const LangOptions & getLangOpts() const
bool CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee)
Check whether we're allowed to call Callee from the current context.
Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
Create a deferred diagnostic, which is emitted only if the function it's attached to is codegen'ed...
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
bool isDiscardableGVALinkage(GVALinkage L)
bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, bool ConsiderCudaAttrs=true)
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Represents a call to a C++ constructor.
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 ...
Represents a C++ constructor 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...
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, C99 6.9p3)
bool PopForceCUDAHostDevice()
Decrements our count of the number of times we've seen a pragma forcing functions to be host device...
PartialDiagnostic PDiag(unsigned DiagID=0)
Build a partial diagnostic.
DiagnosticsEngine & Diags
Defines the clang::Expr interface and subclasses for C++ expressions.
ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig=nullptr, bool IsExecConfig=false)
ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
void CUDASetLambdaAttrs(CXXMethodDecl *Method)
Set device or host device attributes on the given lambda operator() method.
FieldDecl - An instance of this class is created by Sema::ActOnField to represent a member of a struc...
FunctionDecl * getTemplatedDecl() const
Get the underlying function declaration of the template.
CUDADiagBuilder(Kind K, SourceLocation Loc, unsigned DiagID, FunctionDecl *Fn, Sema &S)
CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, bool IgnoreImplicitHDAttr=false)
Determines whether the given function is a CUDA device/host/kernel/etc.
Diagnostic builder for CUDA errors which may or may not be deferred.
static void EmitCallStackNotes(Sema &S, FunctionDecl *FD)
SpecialMemberOverloadResult - The overloading result for a special member function.
ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc)
Represents the results of name lookup.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
unsigned getDiagID() const
const CXXRecordDecl * getParent() const
Returns the parent of this method declaration, which is the class in which this method is defined...
field_range fields() const
RecordDecl * getDecl() const
llvm::DenseMap< CanonicalDeclPtr< FunctionDecl >, std::vector< PartialDiagnosticAt > > CUDADeferredDiags
Diagnostics that are emitted only if we discover that the given function must be codegen'ed.
bool isVariadic() const
Whether this function is variadic.
Scope - A scope is a transient data structure that is used while parsing the program.
bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD)
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
bool isDefined(const FunctionDecl *&Definition) const
isDefined - Returns true if the function is defined at all, including a deleted definition.
bool isAbstract() const
Determine whether this class has a pure virtual function.
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.
void Emit(const DiagnosticBuilder &DB) const
CXXSpecialMember
Kinds of C++ special members.
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...
Sema - This implements semantic analysis and AST building for C.
A little helper class used to produce diagnostics.
llvm::DenseSet< FunctionDeclAndLoc > LocsWithCUDACallDiags
FunctionDecls and SourceLocations for which CheckCUDACall has emitted a (maybe deferred) "bad call" d...
void PushForceCUDAHostDevice()
Increments our count of the number of times we've seen a pragma forcing functions to be host device...
Represents a C++ destructor within a class.
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
Defines the clang::Preprocessor interface.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD)
DeclarationName getDeclName() const
getDeclName - Get the actual, stored name of the declaration, which may be a special name...
DiagnosticsEngine & getDiagnostics() const
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
decl_type * getFirstDecl()
Return the first declaration of this declaration or itself if this is the only declaration.
llvm::DenseMap< CanonicalDeclPtr< FunctionDecl >, FunctionDeclAndLoc > CUDAKnownEmittedFns
An inverse call graph, mapping known-emitted functions to one of their known-emitted callers (plus th...
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
Encodes a location in the source.
unsigned getNumParams() const
getNumParams - Return the number of parameters this function must have based on its FunctionType...
ASTContext & getASTContext() const
Represents a static or instance method of a struct/union/class.
static bool hasAttr(const FunctionDecl *D, bool IgnoreImplicitAttr)
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...
CUDADiagBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID)
Creates a CUDADiagBuilder that emits the diagnostic if the current context is "used as host code"...
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs. ...
FunctionDecl * getcudaConfigureCallDecl()
CUDAFunctionTarget CurrentCUDATarget()
Gets the CUDA target for the current context.
const DiagnosticBuilder & setForceEmit() const
Forces the diagnostic to be emitted.
bool isDynamicClass() const
void checkCUDATargetOverload(FunctionDecl *NewFD, const LookupResult &Previous)
Check whether NewFD is a valid overload for CUDA.
SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis)
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
SourceManager & getSourceManager() const
const T * getAs() const
Member-template getAs<specific type>'.
CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee)
Identifies relative preference of a given Caller/Callee combination, based on their host/device attri...
Represents a C++ base or member initializer.
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
Represents a base class of a C++ class.
static bool IsKnownEmitted(Sema &S, FunctionDecl *FD)
static void EmitDeferredDiags(Sema &S, FunctionDecl *FD)
Represents a C++ struct/union/class.
BoundNodesTreeBuilder *const Builder
static void MarkKnownEmitted(Sema &S, FunctionDecl *OrigCaller, FunctionDecl *OrigCallee, SourceLocation OrigLoc)
DeclContext * CurContext
CurContext - This is the current declaration context of parsing.
A reference to a declared variable, function, enum, etc.
Emit the diagnostic immediately, and, if it's a warning or error, also emit a call stack showing how ...
AttributeList * getNext() const
An l-value expression is a reference to an object with independent storage.
void inheritCUDATargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD)
Copies target attributes from the template TD to the function FD.
A wrapper class around a pointer that always points to its canonical declaration. ...
SourceLocation getLocation() const
NamedDecl - This represents a decl with a name.
Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const
Based on the way the client configured the DiagnosticsEngine object, classify the specified diagnosti...
bool hasTrivialBody() const
hasTrivialBody - Returns whether the function has a trivial body that does not require any specific c...
static void copyAttrIfPresent(Sema &S, FunctionDecl *FD, const FunctionDecl &TemplateFD)
base_class_range vbases()
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
Declaration of a template function.
CUDADiagBuilder CUDADiagIfDeviceCode(SourceLocation Loc, unsigned DiagID)
Creates a CUDADiagBuilder that emits the diagnostic if the current context is "used as device code"...
Attr - This represents one attribute.
Represents a shadow declaration introduced into a scope by a (resolved) using declaration.
AttributeList - Represents a syntactic attribute.