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.");
215 if (Matches.size() <= 1)
218 using Pair = std::pair<DeclAccessPair, FunctionDecl*>;
221 auto GetCFP = [&](
const Pair &Match) {
227 Matches.begin(), Matches.end(),
228 [&](
const Pair &M1,
const Pair &M2) {
return GetCFP(M1) < GetCFP(M2); }));
231 llvm::erase_if(Matches,
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));
585 Builder << FnIt->second.FD;
586 Builder.setForceEmit();
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)
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.
An instance of this class is created to represent a function declaration or definition.
llvm::DenseMap< CanonicalDeclPtr< FunctionDecl >, llvm::MapVector< CanonicalDeclPtr< FunctionDecl >, SourceLocation > > CUDACallGraph
A partial call graph maintained during CUDA compilation to support deferred diagnostics.
A (possibly-)qualified type.
AttributeList * getNext() 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...
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
bool isDiscardableGVALinkage(GVALinkage L)
bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, bool ConsiderCudaAttrs=true)
const DiagnosticBuilder & setForceEmit() const
Forces the diagnostic to be emitted.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Represents a call to a C++ constructor.
bool isDefined(const FunctionDecl *&Definition) const
Returns true if the function is defined at all, including a deleted definition.
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
const T * getAs() const
Member-template getAs<specific type>'.
unsigned getDiagID() const
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.
DeclarationName getDeclName() const
getDeclName - Get the actual, stored name of the declaration, which may be a special name...
bool hasTrivialBody() const
Returns whether the function has a trivial body that does not require any specific codegen...
field_range fields() const
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...
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.
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) 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.
Scope - A scope is a transient data structure that is used while parsing the program.
bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD)
const LangOptions & getLangOpts() const
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.
DiagnosticsEngine & getDiagnostics() const
CXXSpecialMember
Kinds of C++ special members.
Sema - This implements semantic analysis and AST building for C.
A little helper class used to produce diagnostics.
bool isDynamicClass() const
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...
bool isVariadic() const
Whether this function is variadic.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
const FunctionProtoType * T
Represents a C++ destructor within a class.
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Defines the clang::Preprocessor interface.
bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD)
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
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...
RecordDecl * getDecl() const
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...
void Emit(const DiagnosticBuilder &DB) const
ActionResult - This structure is used while parsing/acting on expressions, stmts, etc...
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
ASTContext & getASTContext() const
FunctionDecl * getTemplatedDecl() const
Get the underlying function declaration of the template.
Encodes a location in the source.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
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.
Dataflow Directional Tag Classes.
Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const
Based on the way the client configured the DiagnosticsEngine object, classify the specified diagnosti...
const CXXRecordDecl * getParent() const
Returns the parent of this method declaration, which is the class in which this method is defined...
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
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...
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.
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.
static void MarkKnownEmitted(Sema &S, FunctionDecl *OrigCaller, FunctionDecl *OrigCallee, SourceLocation OrigLoc)
DeclContext * CurContext
CurContext - This is the current declaration context of parsing.
SourceManager & getSourceManager() const
StringRef getName() const
getName - Get the name of identifier for this declaration as a StringRef.
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 ...
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. ...
NamedDecl - This represents a decl with a name.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
static void copyAttrIfPresent(Sema &S, FunctionDecl *FD, const FunctionDecl &TemplateFD)
base_class_range vbases()
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.
SourceLocation getLocation() const
Represents a shadow declaration introduced into a scope by a (resolved) using declaration.
AttributeList - Represents a syntactic attribute.