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 Diag(LLLLoc, diag::err_undeclared_var_use)
47 << (
getLangOpts().HIP ?
"hipConfigureCall" :
"cudaConfigureCall"));
54 return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc,
nullptr,
60 bool HasHostAttr =
false;
61 bool HasDeviceAttr =
false;
62 bool HasGlobalAttr =
false;
63 bool HasInvalidTargetAttr =
false;
65 switch (AL.getKind()) {
66 case ParsedAttr::AT_CUDAGlobal:
69 case ParsedAttr::AT_CUDAHost:
72 case ParsedAttr::AT_CUDADevice:
75 case ParsedAttr::AT_CUDAInvalidTarget:
76 HasInvalidTargetAttr =
true;
83 if (HasInvalidTargetAttr)
89 if (HasHostAttr && HasDeviceAttr)
101 return isa<A>(Attribute) &&
102 !(IgnoreImplicitAttr && Attribute->isImplicit());
108 bool IgnoreImplicitHDAttr) {
113 if (D->
hasAttr<CUDAInvalidTargetAttr>())
116 if (D->
hasAttr<CUDAGlobalAttr>())
119 if (hasAttr<CUDADeviceAttr>(D, IgnoreImplicitHDAttr)) {
120 if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr))
123 }
else if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) {
125 }
else if (D->
isImplicit() && !IgnoreImplicitHDAttr) {
165 assert(Callee &&
"Callee must be valid.");
185 if (CalleeTarget == CallerTarget ||
211 llvm_unreachable(
"All cases should've been handled by now.");
217 if (Matches.size() <= 1)
220 using Pair = std::pair<DeclAccessPair, FunctionDecl*>;
223 auto GetCFP = [&](
const Pair &Match) {
229 Matches.begin(), Matches.end(),
230 [&](
const Pair &M1,
const Pair &M2) {
return GetCFP(M1) < GetCFP(M2); }));
233 llvm::erase_if(Matches,
234 [&](
const Pair &Match) {
return GetCFP(Match) < BestCFP; });
254 *ResolvedTarget = Target2;
256 *ResolvedTarget = Target1;
257 }
else if (Target1 != Target2) {
260 *ResolvedTarget = Target1;
281 for (
const auto &B : ClassDecl->
bases()) {
282 if (!B.isVirtual()) {
288 for (
const auto &VB : ClassDecl->
vbases()) {
289 Bases.push_back(&VB);
293 for (
const auto *B : Bases) {
308 if (!SMOR.getMethod())
312 if (!InferredTarget.hasValue()) {
313 InferredTarget = BaseMethodTarget;
316 InferredTarget.getValue(), BaseMethodTarget,
317 InferredTarget.getPointer());
318 if (ResolutionError) {
321 diag::note_implicit_member_target_infer_collision)
322 << (
unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
324 MemberDecl->
addAttr(CUDAInvalidTargetAttr::CreateImplicit(
Context));
331 for (
const auto *F : ClassDecl->
fields()) {
332 if (F->isInvalidDecl()) {
345 ConstRHS && !F->isMutable(),
351 if (!SMOR.getMethod())
356 if (!InferredTarget.hasValue()) {
357 InferredTarget = FieldMethodTarget;
360 InferredTarget.getValue(), FieldMethodTarget,
361 InferredTarget.getPointer());
362 if (ResolutionError) {
365 diag::note_implicit_member_target_infer_collision)
366 << (
unsigned)CSM << InferredTarget.getValue()
367 << FieldMethodTarget;
369 MemberDecl->
addAttr(CUDAInvalidTargetAttr::CreateImplicit(
Context));
375 if (InferredTarget.hasValue()) {
376 if (InferredTarget.getValue() ==
CFT_Device) {
378 }
else if (InferredTarget.getValue() ==
CFT_Host) {
419 dyn_cast<CXXConstructExpr>(CI->getInit()))
466 ->getBaseElementTypeUnsafe()
467 ->getAsCXXRecordDecl())
480 if (VD->
hasAttr<CUDADeviceAttr>() || VD->
hasAttr<CUDAConstantAttr>() ||
481 VD->
hasAttr<CUDASharedAttr>()) {
483 bool AllowedInit =
false;
491 (VD->
hasAttr<CUDADeviceAttr>() || VD->
hasAttr<CUDAConstantAttr>()))
503 ? diag::err_shared_var_init
504 : diag::err_dynamic_var_init)
513 InitFn = CE->getConstructor();
514 }
else if (
const CallExpr *CE = dyn_cast<CallExpr>(Init)) {
515 InitFn = CE->getDirectCallee();
521 << InitFnTarget << InitFn;
543 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
545 if (ForceCUDAHostDeviceDepth > 0) {
546 if (!NewD->
hasAttr<CUDAHostAttr>())
548 if (!NewD->
hasAttr<CUDADeviceAttr>())
555 NewD->
hasAttr<CUDADeviceAttr>() || NewD->
hasAttr<CUDAGlobalAttr>())
560 auto IsMatchingDeviceFn = [&](
NamedDecl *D) {
562 D = Using->getTargetDecl();
564 return OldD && OldD->
hasAttr<CUDADeviceAttr>() &&
565 !OldD->
hasAttr<CUDAHostAttr>() &&
569 auto It = llvm::find_if(Previous, IsMatchingDeviceFn);
570 if (It != Previous.
end()) {
578 diag::err_cuda_unattributed_constexpr_cannot_overload_device)
581 diag::note_cuda_conflicting_device_function_declared_here);
617 : S(S), Loc(Loc), DiagID(DiagID), Fn(Fn),
618 ShowCallStack(K == K_ImmediateWithCallStack || K == K_Deferred) {
624 ImmediateDiag.emplace(S.
Diag(Loc, DiagID));
627 assert(Fn &&
"Must have a function to attach the deferred diag to.");
628 PartialDiag.emplace(S.
PDiag(DiagID));
639 S.
Diags.
Report(FnIt->second.Loc, diag::note_called_by));
640 Builder << FnIt->second.FD;
641 Builder.setForceEmit();
653 ImmediateDiag.reset();
654 if (IsWarningOrError && ShowCallStack)
656 }
else if (PartialDiag) {
657 assert(ShowCallStack &&
"Must always show call stack for deferred diags.");
698 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
725 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
754 bool HasWarningOrError =
false;
769 if (HasWarningOrError)
793 llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen;
794 Seen.insert(OrigCallee);
795 while (!Worklist.empty()) {
796 CallInfo
C = Worklist.pop_back_val();
798 "Worklist should not contain known-emitted functions.");
805 if (
auto *Templ = C.Callee->getPrimaryTemplate()) {
808 Seen.insert(TemplFD);
810 { C.Caller, TemplFD, C.Loc});
825 Seen.insert(NewCallee);
827 { C.Callee, NewCallee, CallLoc});
837 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
838 assert(Callee &&
"Callee may not be null.");
848 if (CallerKnownEmitted) {
869 assert(Caller &&
"WrongSide calls require a non-null caller");
890 CUDADiagBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *
this)
900 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
901 if (Method->
hasAttr<CUDAHostAttr>() || Method->
hasAttr<CUDADeviceAttr>())
917 assert(
getLangOpts().CUDA &&
"Should only be called during CUDA compilation");
930 if (NewTarget != OldTarget &&
936 << NewTarget << NewFD->
getDeclName() << OldTarget << OldFD;
937 Diag(OldFD->getLocation(), diag::note_previous_declaration);
944 template <
typename AttrTy>
947 if (AttrTy *Attribute = TemplateFD.
getAttr<AttrTy>()) {
948 AttrTy *Clone = Attribute->clone(S.
Context);
949 Clone->setInherited(
true);
957 copyAttrIfPresent<CUDAGlobalAttr>(*
this, FD, TemplateFD);
958 copyAttrIfPresent<CUDAHostAttr>(*
this, FD, TemplateFD);
959 copyAttrIfPresent<CUDADeviceAttr>(*
this, FD, TemplateFD);
Defines the clang::ASTContext interface.
FunctionDecl * getDefinition()
Get the definition for this declaration.
Represents 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.
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 has a definition that does not need to be instantiated.
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...
Represents a variable declaration or definition.
PartialDiagnostic PDiag(unsigned DiagID=0)
Build a partial diagnostic.
DiagnosticsEngine & Diags
const T * getAs() const
Member-template getAs<specific type>'.
unsigned getDiagID() const
bool isInvalidDecl() 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
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.
Represents a member of a struct/union/class.
CUDADiagBuilder(Kind K, SourceLocation Loc, unsigned DiagID, FunctionDecl *Fn, Sema &S)
bool isReferenceType() const
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.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isDynamicClass() const
llvm::DenseSet< FunctionDeclAndLoc > LocsWithCUDACallDiags
FunctionDecls and SourceLocations for which CheckCUDACall has emitted a (maybe deferred) "bad call" d...
This represents one expression.
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.
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
void checkAllowedCUDAInitializer(VarDecl *VD)
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.
ParsedAttr - Represents a syntactic attribute.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs. ...
Represents a static or instance method of a struct/union/class.
static bool hasAttr(const FunctionDecl *D, bool IgnoreImplicitAttr)
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
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"...
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 Expr * getInit() const
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.
bool isConstantInitializer(ASTContext &Ctx, bool ForRef, const Expr **Culprit=nullptr) const
isConstantInitializer - Returns true if this expression can be emitted to IR as a constant...
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
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
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
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. ...
This represents a decl that may have 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.