417 changes: 221 additions & 196 deletions clang/lib/Sema/SemaCUDA.cpp

Large diffs are not rendered by default.

20 changes: 16 additions & 4 deletions clang/lib/Sema/SemaCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,22 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
howManyCandidates = OCD_AmbiguousCandidates;
break;

case OR_Deleted:
msg = diag::err_ovl_deleted_conversion_in_cast;
howManyCandidates = OCD_ViableCandidates;
break;
case OR_Deleted: {
OverloadCandidateSet::iterator Best;
[[maybe_unused]] OverloadingResult Res =
candidates.BestViableFunction(S, range.getBegin(), Best);
assert(Res == OR_Deleted && "Inconsistent overload resolution");

StringLiteral *Msg = Best->Function->getDeletedMessage();
candidates.NoteCandidates(
PartialDiagnosticAt(range.getBegin(),
S.PDiag(diag::err_ovl_deleted_conversion_in_cast)
<< CT << srcType << destType << (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef())
<< range << src->getSourceRange()),
S, OCD_ViableCandidates, src);
return true;
}
}

candidates.NoteCandidates(
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19710,6 +19710,27 @@ bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const {
return isLayoutCompatible(getASTContext(), T1, T2);
}

//===-------------- Pointer interconvertibility ----------------------------//

bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base,
const TypeSourceInfo *Derived) {
QualType BaseT = Base->getType()->getCanonicalTypeUnqualified();
QualType DerivedT = Derived->getType()->getCanonicalTypeUnqualified();

if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() &&
getASTContext().hasSameType(BaseT, DerivedT))
return true;

if (!IsDerivedFrom(Derived->getTypeLoc().getBeginLoc(), DerivedT, BaseT))
return false;

// Per [basic.compound]/4.3, containing object has to be standard-layout.
if (DerivedT->getAsCXXRecordDecl()->isStandardLayout())
return true;

return false;
}

//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//

/// Given a type tag expression find the type tag itself.
Expand Down
216 changes: 58 additions & 158 deletions clang/lib/Sema/SemaDecl.cpp

Large diffs are not rendered by default.

79 changes: 18 additions & 61 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Assumptions.h"
#include "llvm/MC/MCSectionMachO.h"
Expand Down Expand Up @@ -5097,8 +5100,8 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
if (S.getLangOpts().CUDA && VD->hasLocalStorage() &&
S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
<< S.CurrentCUDATarget())
S.CUDA().DiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
<< llvm::to_underlying(S.CUDA().CurrentTarget()))
return;
D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL));
}
Expand Down Expand Up @@ -5187,8 +5190,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Diagnostic is emitted elsewhere: here we store the (valid) AL
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
CallingConv CC;
if (S.CheckCallingConvAttr(AL, CC, /*FD*/ nullptr,
S.IdentifyCUDATarget(dyn_cast<FunctionDecl>(D))))
if (S.CheckCallingConvAttr(
AL, CC, /*FD*/ nullptr,
S.CUDA().IdentifyTarget(dyn_cast<FunctionDecl>(D))))
return;

if (!isa<ObjCMethodDecl>(D)) {
Expand Down Expand Up @@ -5492,22 +5496,22 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
// on their host/device attributes.
if (LangOpts.CUDA) {
auto *Aux = Context.getAuxTargetInfo();
assert(FD || CFT != CFT_InvalidTarget);
auto CudaTarget = FD ? IdentifyCUDATarget(FD) : CFT;
assert(FD || CFT != CUDAFunctionTarget::InvalidTarget);
auto CudaTarget = FD ? CUDA().IdentifyTarget(FD) : CFT;
bool CheckHost = false, CheckDevice = false;
switch (CudaTarget) {
case CFT_HostDevice:
case CUDAFunctionTarget::HostDevice:
CheckHost = true;
CheckDevice = true;
break;
case CFT_Host:
case CUDAFunctionTarget::Host:
CheckHost = true;
break;
case CFT_Device:
case CFT_Global:
case CUDAFunctionTarget::Device:
case CUDAFunctionTarget::Global:
CheckDevice = true;
break;
case CFT_InvalidTarget:
case CUDAFunctionTarget::InvalidTarget:
llvm_unreachable("unexpected cuda target");
}
auto *HostTI = LangOpts.CUDAIsDevice ? Aux : &TI;
Expand Down Expand Up @@ -7238,24 +7242,11 @@ static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}

HLSLNumThreadsAttr *NewAttr = S.mergeHLSLNumThreadsAttr(D, AL, X, Y, Z);
HLSLNumThreadsAttr *NewAttr = S.HLSL().mergeNumThreadsAttr(D, AL, X, Y, Z);
if (NewAttr)
D->addAttr(NewAttr);
}

HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D,
const AttributeCommonInfo &AL,
int X, int Y, int Z) {
if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
Diag(AL.getLoc(), diag::note_conflicting_attribute);
}
return nullptr;
}
return ::new (Context) HLSLNumThreadsAttr(Context, AL, X, Y, Z);
}

static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
if (!T->hasUnsignedIntegerRepresentation())
return false;
Expand Down Expand Up @@ -7299,24 +7290,11 @@ static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {

// FIXME: check function match the shader stage.

HLSLShaderAttr *NewAttr = S.mergeHLSLShaderAttr(D, AL, ShaderType);
HLSLShaderAttr *NewAttr = S.HLSL().mergeShaderAttr(D, AL, ShaderType);
if (NewAttr)
D->addAttr(NewAttr);
}

HLSLShaderAttr *
Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLShaderAttr::ShaderType ShaderType) {
if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
if (NT->getType() != ShaderType) {
Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
Diag(AL.getLoc(), diag::note_conflicting_attribute);
}
return nullptr;
}
return HLSLShaderAttr::Create(Context, ShaderType, AL);
}

static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
StringRef Space = "space0";
Expand Down Expand Up @@ -7391,34 +7369,13 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,

static void handleHLSLParamModifierAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
HLSLParamModifierAttr *NewAttr = S.mergeHLSLParamModifierAttr(
HLSLParamModifierAttr *NewAttr = S.HLSL().mergeParamModifierAttr(
D, AL,
static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
if (NewAttr)
D->addAttr(NewAttr);
}

HLSLParamModifierAttr *
Sema::mergeHLSLParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLParamModifierAttr::Spelling Spelling) {
// We can only merge an `in` attribute with an `out` attribute. All other
// combinations of duplicated attributes are ill-formed.
if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) {
if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) ||
(PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) {
D->dropAttr<HLSLParamModifierAttr>();
SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()};
return HLSLParamModifierAttr::Create(
Context, /*MergedSpelling=*/true, AdjustedRange,
HLSLParamModifierAttr::Keyword_inout);
}
Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL;
Diag(PA->getLocation(), diag::note_conflicting_attribute);
return nullptr;
}
return HLSLParamModifierAttr::Create(Context, AL);
}

static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.LangOpts.CPlusPlus) {
S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
Expand Down
549 changes: 300 additions & 249 deletions clang/lib/Sema/SemaDeclCXX.cpp

Large diffs are not rendered by default.

46 changes: 27 additions & 19 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ConvertUTF.h"
Expand Down Expand Up @@ -271,8 +273,11 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
Diag(Loc, diag::err_deleted_inherited_ctor_use)
<< Ctor->getParent()
<< Ctor->getInheritedConstructor().getConstructor()->getParent();
else
Diag(Loc, diag::err_deleted_function_use);
else {
StringLiteral *Msg = FD->getDeletedMessage();
Diag(Loc, diag::err_deleted_function_use)
<< (Msg != nullptr) << (Msg ? Msg->getString() : StringRef());
}
NoteDeletedFunction(FD);
return true;
}
Expand Down Expand Up @@ -307,7 +312,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
DeduceReturnType(FD, Loc))
return true;

if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
if (getLangOpts().CUDA && !CUDA().CheckCall(Loc, FD))
return true;

}
Expand Down Expand Up @@ -14858,8 +14863,8 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
return QualType();
} else if (ResType->isAnyComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
S.Diag(OpLoc, diag::ext_integer_increment_complex)
<< ResType << Op->getSourceRange();
S.Diag(OpLoc, diag::ext_increment_complex)
<< IsInc << Op->getSourceRange();
} else if (ResType->isPlaceholderType()) {
ExprResult PR = S.CheckPlaceholderExpr(Op);
if (PR.isInvalid()) return QualType();
Expand Down Expand Up @@ -17306,8 +17311,9 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
// CUDA device code does not support varargs.
if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
if (const FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
CUDAFunctionTarget T = IdentifyCUDATarget(F);
if (T == CFT_Global || T == CFT_Device || T == CFT_HostDevice)
CUDAFunctionTarget T = CUDA().IdentifyTarget(F);
if (T == CUDAFunctionTarget::Global || T == CUDAFunctionTarget::Device ||
T == CUDAFunctionTarget::HostDevice)
return ExprError(Diag(E->getBeginLoc(), diag::err_va_arg_in_device));
}
}
Expand Down Expand Up @@ -18959,7 +18965,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
checkSpecializationReachability(Loc, Func);

if (getLangOpts().CUDA)
CheckCUDACall(Loc, Func);
CUDA().CheckCall(Loc, Func);

// If we need a definition, try to create one.
if (NeedDefinition && !Func->getBody()) {
Expand Down Expand Up @@ -19106,7 +19112,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// side. Therefore keep trying until it is recorded.
if (LangOpts.OffloadImplicitHostDeviceTemplates && LangOpts.CUDAIsDevice &&
!getASTContext().CUDAImplicitHostDeviceFunUsedByDevice.count(Func))
CUDARecordImplicitHostDeviceFuncUsedByDevice(Func);
CUDA().RecordImplicitHostDeviceFuncUsedByDevice(Func);

// If this is the first "real" use, act on that.
if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) {
Expand Down Expand Up @@ -19179,26 +19185,28 @@ MarkVarDeclODRUsed(ValueDecl *V, SourceLocation Loc, Sema &SemaRef,

if (SemaRef.LangOpts.CUDA && Var->hasGlobalStorage()) {
auto *FD = dyn_cast_or_null<FunctionDecl>(SemaRef.CurContext);
auto VarTarget = SemaRef.IdentifyCUDATarget(Var);
auto UserTarget = SemaRef.IdentifyCUDATarget(FD);
if (VarTarget == Sema::CVT_Host &&
(UserTarget == Sema::CFT_Device || UserTarget == Sema::CFT_HostDevice ||
UserTarget == Sema::CFT_Global)) {
auto VarTarget = SemaRef.CUDA().IdentifyTarget(Var);
auto UserTarget = SemaRef.CUDA().IdentifyTarget(FD);
if (VarTarget == SemaCUDA::CVT_Host &&
(UserTarget == CUDAFunctionTarget::Device ||
UserTarget == CUDAFunctionTarget::HostDevice ||
UserTarget == CUDAFunctionTarget::Global)) {
// Diagnose ODR-use of host global variables in device functions.
// Reference of device global variables in host functions is allowed
// through shadow variables therefore it is not diagnosed.
if (SemaRef.LangOpts.CUDAIsDevice && !SemaRef.LangOpts.HIPStdPar) {
SemaRef.targetDiag(Loc, diag::err_ref_bad_target)
<< /*host*/ 2 << /*variable*/ 1 << Var << UserTarget;
<< /*host*/ 2 << /*variable*/ 1 << Var
<< llvm::to_underlying(UserTarget);
SemaRef.targetDiag(Var->getLocation(),
Var->getType().isConstQualified()
? diag::note_cuda_const_var_unpromoted
: diag::note_cuda_host_var);
}
} else if (VarTarget == Sema::CVT_Device &&
} else if (VarTarget == SemaCUDA::CVT_Device &&
!Var->hasAttr<CUDASharedAttr>() &&
(UserTarget == Sema::CFT_Host ||
UserTarget == Sema::CFT_HostDevice)) {
(UserTarget == CUDAFunctionTarget::Host ||
UserTarget == CUDAFunctionTarget::HostDevice)) {
// Record a CUDA/HIP device side variable if it is ODR-used
// by host code. This is done conservatively, when the variable is
// referenced in any of the following contexts:
Expand Down Expand Up @@ -20704,7 +20712,7 @@ static void FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter(
if (MD->getType().isNull())
continue;

const auto *Ty = cast<FunctionProtoType>(MD->getType());
const auto *Ty = MD->getType()->getAs<FunctionProtoType>();
if (!Ty || !MD->isExplicitObjectMemberFunction() ||
!Ty->getParamType(0)->isDependentType())
continue;
Expand Down
116 changes: 66 additions & 50 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TypeSize.h"
Expand Down Expand Up @@ -883,8 +885,8 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,

// Exceptions aren't allowed in CUDA device code.
if (getLangOpts().CUDA)
CUDADiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions)
<< "throw" << CurrentCUDATarget();
CUDA().DiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions)
<< "throw" << llvm::to_underlying(CUDA().CurrentTarget());

if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
Expand Down Expand Up @@ -1488,7 +1490,7 @@ void Sema::MarkThisReferenced(CXXThisExpr *This) {
if (MD->getType().isNull())
return false;

const auto *Ty = cast<FunctionProtoType>(MD->getType());
const auto *Ty = MD->getType()->getAs<FunctionProtoType>();
return Ty && MD->isExplicitObjectMemberFunction() &&
Ty->getParamType(0)->isDependentType();
}
Expand Down Expand Up @@ -1707,17 +1709,17 @@ bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) {
// [CUDA] Ignore this function, if we can't call it.
const FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true);
if (getLangOpts().CUDA) {
auto CallPreference = IdentifyCUDAPreference(Caller, Method);
auto CallPreference = CUDA().IdentifyPreference(Caller, Method);
// If it's not callable at all, it's not the right function.
if (CallPreference < CFP_WrongSide)
if (CallPreference < SemaCUDA::CFP_WrongSide)
return false;
if (CallPreference == CFP_WrongSide) {
if (CallPreference == SemaCUDA::CFP_WrongSide) {
// Maybe. We have to check if there are better alternatives.
DeclContext::lookup_result R =
Method->getDeclContext()->lookup(Method->getDeclName());
for (const auto *D : R) {
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (IdentifyCUDAPreference(Caller, FD) > CFP_WrongSide)
if (CUDA().IdentifyPreference(Caller, FD) > SemaCUDA::CFP_WrongSide)
return false;
}
}
Expand All @@ -1736,7 +1738,7 @@ bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) {
return llvm::none_of(PreventedBy, [&](const FunctionDecl *FD) {
assert(FD->getNumParams() == 1 &&
"Only single-operand functions should be in PreventedBy");
return IdentifyCUDAPreference(Caller, FD) >= CFP_HostDevice;
return CUDA().IdentifyPreference(Caller, FD) >= SemaCUDA::CFP_HostDevice;
});
}

Expand Down Expand Up @@ -1773,7 +1775,7 @@ namespace {
UsualDeallocFnInfo(Sema &S, DeclAccessPair Found)
: Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())),
Destroying(false), HasSizeT(false), HasAlignValT(false),
CUDAPref(Sema::CFP_Native) {
CUDAPref(SemaCUDA::CFP_Native) {
// A function template declaration is never a usual deallocation function.
if (!FD)
return;
Expand All @@ -1799,7 +1801,7 @@ namespace {

// In CUDA, determine how much we'd like / dislike to call this.
if (S.getLangOpts().CUDA)
CUDAPref = S.IdentifyCUDAPreference(
CUDAPref = S.CUDA().IdentifyPreference(
S.getCurFunctionDecl(/*AllowLambda=*/true), FD);
}

Expand Down Expand Up @@ -1830,7 +1832,7 @@ namespace {
DeclAccessPair Found;
FunctionDecl *FD;
bool Destroying, HasSizeT, HasAlignValT;
Sema::CUDAFunctionPreference CUDAPref;
SemaCUDA::CUDAFunctionPreference CUDAPref;
};
}

Expand All @@ -1854,7 +1856,7 @@ static UsualDeallocFnInfo resolveDeallocationOverload(
for (auto I = R.begin(), E = R.end(); I != E; ++I) {
UsualDeallocFnInfo Info(S, I.getPair());
if (!Info || !isNonPlacementDeallocationFunction(S, Info.FD) ||
Info.CUDAPref == Sema::CFP_Never)
Info.CUDAPref == SemaCUDA::CFP_Never)
continue;

if (!Best) {
Expand Down Expand Up @@ -2714,13 +2716,9 @@ static bool resolveAllocationOverload(
return true;

case OR_Deleted: {
if (Diagnose) {
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_deleted_call)
<< R.getLookupName() << Range),
S, OCD_AllCandidates, Args);
}
if (Diagnose)
S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(),
Candidates, Best->Function, Args);
return true;
}
}
Expand Down Expand Up @@ -2955,8 +2953,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
}

if (getLangOpts().CUDA)
EraseUnwantedCUDAMatches(getCurFunctionDecl(/*AllowLambda=*/true),
Matches);
CUDA().EraseUnwantedMatches(getCurFunctionDecl(/*AllowLambda=*/true),
Matches);
} else {
// C++1y [expr.new]p22:
// For a non-placement allocation function, the normal deallocation
Expand Down Expand Up @@ -3374,7 +3372,9 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
// FIXME: DiagnoseUseOfDecl?
if (Operator->isDeleted()) {
if (Diagnose) {
Diag(StartLoc, diag::err_deleted_function_use);
StringLiteral *Msg = Operator->getDeletedMessage();
Diag(StartLoc, diag::err_deleted_function_use)
<< (Msg != nullptr) << (Msg ? Msg->getString() : StringRef());
NoteDeletedFunction(Operator);
}
return true;
Expand Down Expand Up @@ -3978,14 +3978,11 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
S, OCD_AmbiguousCandidates, Args);
return true;

case OR_Deleted: {
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call)
<< R.getLookupName() << Range),
S, OCD_AllCandidates, Args);
case OR_Deleted:
S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(),
Candidates, Best->Function, Args);
return true;
}
}
llvm_unreachable("Unreachable, bad result from BestViableFunction");
}

Expand Down Expand Up @@ -5010,6 +5007,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return From;
}

/// Checks that type T is not a VLA.
///
/// @returns @c true if @p T is VLA and a diagnostic was emitted,
/// @c false otherwise.
static bool DiagnoseVLAInCXXTypeTrait(Sema &S, const TypeSourceInfo *T,
clang::tok::TokenKind TypeTraitID) {
if (!T->getType()->isVariableArrayType())
return false;

S.Diag(T->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
<< 1 << TypeTraitID;
return true;
}

/// Check the completeness of a type in a unary type trait.
///
/// If the particular type trait requires a complete type, tries to complete
Expand Down Expand Up @@ -5186,7 +5197,9 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
}

static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
SourceLocation KeyLoc, QualType T) {
SourceLocation KeyLoc,
TypeSourceInfo *TInfo) {
QualType T = TInfo->getType();
assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");

ASTContext &C = Self.Context;
Expand All @@ -5203,21 +5216,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
case UTT_IsArray:
return T->isArrayType();
case UTT_IsBoundedArray:
if (!T->isVariableArrayType()) {
return T->isArrayType() && !T->isIncompleteArrayType();
}

Self.Diag(KeyLoc, diag::err_vla_unsupported)
<< 1 << tok::kw___is_bounded_array;
return false;
if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_bounded_array))
return false;
return T->isArrayType() && !T->isIncompleteArrayType();
case UTT_IsUnboundedArray:
if (!T->isVariableArrayType()) {
return T->isIncompleteArrayType();
}

Self.Diag(KeyLoc, diag::err_vla_unsupported)
<< 1 << tok::kw___is_unbounded_array;
return false;
if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_unbounded_array))
return false;
return T->isIncompleteArrayType();
case UTT_IsPointer:
return T->isAnyPointerType();
case UTT_IsNullPointer:
Expand Down Expand Up @@ -5629,7 +5634,7 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
return false;

if (Kind <= UTT_Last)
return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType());
return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]);

// Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
// alongside the IsConstructible traits to avoid duplication.
Expand Down Expand Up @@ -6091,13 +6096,24 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
diag::err_incomplete_type);

if (LhsT->isVariableArrayType())
Self.Diag(Lhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
<< 1 << tok::kw___is_layout_compatible;
if (RhsT->isVariableArrayType())
Self.Diag(Rhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
<< 1 << tok::kw___is_layout_compatible;
DiagnoseVLAInCXXTypeTrait(Self, Lhs, tok::kw___is_layout_compatible);
DiagnoseVLAInCXXTypeTrait(Self, Rhs, tok::kw___is_layout_compatible);

return Self.IsLayoutCompatible(LhsT, RhsT);
}
case BTT_IsPointerInterconvertibleBaseOf: {
if (LhsT->isStructureOrClassType() && RhsT->isStructureOrClassType() &&
!Self.getASTContext().hasSameUnqualifiedType(LhsT, RhsT)) {
Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
diag::err_incomplete_type);
}

DiagnoseVLAInCXXTypeTrait(Self, Lhs,
tok::kw___is_pointer_interconvertible_base_of);
DiagnoseVLAInCXXTypeTrait(Self, Rhs,
tok::kw___is_pointer_interconvertible_base_of);

return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs);
}
default: llvm_unreachable("not a BTT");
}
Expand Down
186 changes: 180 additions & 6 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,25 @@
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaHLSL.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/TargetParser/Triple.h"
#include <iterator>

using namespace clang;

SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {}

Decl *SemaHLSL::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
SourceLocation KwLoc,
IdentifierInfo *Ident,
SourceLocation IdentLoc,
SourceLocation LBrace) {
Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
SourceLocation KwLoc, IdentifierInfo *Ident,
SourceLocation IdentLoc,
SourceLocation LBrace) {
// For anonymous namespace, take the location of the left brace.
DeclContext *LexicalParent = SemaRef.getCurLexicalContext();
HLSLBufferDecl *Result = HLSLBufferDecl::Create(
Expand All @@ -31,8 +39,174 @@ Decl *SemaHLSL::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
return Result;
}

void SemaHLSL::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) {
void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
BufDecl->setRBraceLoc(RBrace);
SemaRef.PopDeclContext();
}

HLSLNumThreadsAttr *SemaHLSL::mergeNumThreadsAttr(Decl *D,
const AttributeCommonInfo &AL,
int X, int Y, int Z) {
if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
Diag(AL.getLoc(), diag::note_conflicting_attribute);
}
return nullptr;
}
return ::new (getASTContext())
HLSLNumThreadsAttr(getASTContext(), AL, X, Y, Z);
}

HLSLShaderAttr *
SemaHLSL::mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLShaderAttr::ShaderType ShaderType) {
if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
if (NT->getType() != ShaderType) {
Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
Diag(AL.getLoc(), diag::note_conflicting_attribute);
}
return nullptr;
}
return HLSLShaderAttr::Create(getASTContext(), ShaderType, AL);
}

HLSLParamModifierAttr *
SemaHLSL::mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLParamModifierAttr::Spelling Spelling) {
// We can only merge an `in` attribute with an `out` attribute. All other
// combinations of duplicated attributes are ill-formed.
if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) {
if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) ||
(PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) {
D->dropAttr<HLSLParamModifierAttr>();
SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()};
return HLSLParamModifierAttr::Create(
getASTContext(), /*MergedSpelling=*/true, AdjustedRange,
HLSLParamModifierAttr::Keyword_inout);
}
Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL;
Diag(PA->getLocation(), diag::note_conflicting_attribute);
return nullptr;
}
return HLSLParamModifierAttr::Create(getASTContext(), AL);
}

void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
auto &TargetInfo = getASTContext().getTargetInfo();

if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry)
return;

StringRef Env = TargetInfo.getTriple().getEnvironmentName();
HLSLShaderAttr::ShaderType ShaderType;
if (HLSLShaderAttr::ConvertStrToShaderType(Env, ShaderType)) {
if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) {
// The entry point is already annotated - check that it matches the
// triple.
if (Shader->getType() != ShaderType) {
Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch)
<< Shader;
FD->setInvalidDecl();
}
} else {
// Implicitly add the shader attribute if the entry function isn't
// explicitly annotated.
FD->addAttr(HLSLShaderAttr::CreateImplicit(getASTContext(), ShaderType,
FD->getBeginLoc()));
}
} else {
switch (TargetInfo.getTriple().getEnvironment()) {
case llvm::Triple::UnknownEnvironment:
case llvm::Triple::Library:
break;
default:
llvm_unreachable("Unhandled environment in triple");
}
}
}

void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
assert(ShaderAttr && "Entry point has no shader attribute");
HLSLShaderAttr::ShaderType ST = ShaderAttr->getType();

switch (ST) {
case HLSLShaderAttr::Pixel:
case HLSLShaderAttr::Vertex:
case HLSLShaderAttr::Geometry:
case HLSLShaderAttr::Hull:
case HLSLShaderAttr::Domain:
case HLSLShaderAttr::RayGeneration:
case HLSLShaderAttr::Intersection:
case HLSLShaderAttr::AnyHit:
case HLSLShaderAttr::ClosestHit:
case HLSLShaderAttr::Miss:
case HLSLShaderAttr::Callable:
if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
DiagnoseAttrStageMismatch(NT, ST,
{HLSLShaderAttr::Compute,
HLSLShaderAttr::Amplification,
HLSLShaderAttr::Mesh});
FD->setInvalidDecl();
}
break;

case HLSLShaderAttr::Compute:
case HLSLShaderAttr::Amplification:
case HLSLShaderAttr::Mesh:
if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
<< HLSLShaderAttr::ConvertShaderTypeToStr(ST);
FD->setInvalidDecl();
}
break;
}

for (ParmVarDecl *Param : FD->parameters()) {
if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) {
CheckSemanticAnnotation(FD, Param, AnnotationAttr);
} else {
// FIXME: Handle struct parameters where annotations are on struct fields.
// See: https://github.com/llvm/llvm-project/issues/57875
Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
Diag(Param->getLocation(), diag::note_previous_decl) << Param;
FD->setInvalidDecl();
}
}
// FIXME: Verify return type semantic annotation.
}

void SemaHLSL::CheckSemanticAnnotation(
FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAnnotationAttr *AnnotationAttr) {
auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
assert(ShaderAttr && "Entry point has no shader attribute");
HLSLShaderAttr::ShaderType ST = ShaderAttr->getType();

switch (AnnotationAttr->getKind()) {
case attr::HLSLSV_DispatchThreadID:
case attr::HLSLSV_GroupIndex:
if (ST == HLSLShaderAttr::Compute)
return;
DiagnoseAttrStageMismatch(AnnotationAttr, ST, {HLSLShaderAttr::Compute});
break;
default:
llvm_unreachable("Unknown HLSLAnnotationAttr");
}
}

void SemaHLSL::DiagnoseAttrStageMismatch(
const Attr *A, HLSLShaderAttr::ShaderType Stage,
std::initializer_list<HLSLShaderAttr::ShaderType> AllowedStages) {
SmallVector<StringRef, 8> StageStrings;
llvm::transform(AllowedStages, std::back_inserter(StageStrings),
[](HLSLShaderAttr::ShaderType ST) {
return StringRef(
HLSLShaderAttr::ConvertShaderTypeToStr(ST));
});
Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
<< A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage)
<< (AllowedStages.size() != 1) << join(StageStrings, ", ");
}
25 changes: 18 additions & 7 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
Expand Down Expand Up @@ -9762,12 +9763,15 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}
case OR_Deleted: {
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
<< OnlyArg->getType() << DestType.getNonReferenceType()
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);

StringLiteral *Msg = Best->Function->getDeletedMessage();
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
<< OnlyArg->getType() << DestType.getNonReferenceType()
<< (Msg != nullptr) << (Msg ? Msg->getString() : StringRef())
<< Args[0]->getSourceRange();
if (Ovl == OR_Deleted) {
S.NoteDeletedFunction(Best->Function);
} else {
Expand Down Expand Up @@ -10023,11 +10027,15 @@ bool InitializationSequence::Diagnose(Sema &S,
// implicit.
if (S.isImplicitlyDeleted(Best->Function))
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_special_init)
<< S.getSpecialMember(cast<CXXMethodDecl>(Best->Function))
<< DestType << ArgsRange;
else
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
<< llvm::to_underlying(
S.getSpecialMember(cast<CXXMethodDecl>(Best->Function)))
<< DestType << ArgsRange;
else {
StringLiteral *Msg = Best->Function->getDeletedMessage();
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
<< DestType << (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef()) << ArgsRange;
}

S.NoteDeletedFunction(Best->Function);
break;
Expand Down Expand Up @@ -11059,6 +11067,9 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
}

case OR_Deleted: {
// FIXME: There are no tests for this diagnostic, and it doesn't seem
// like we ever get here; attempts to trigger this seem to yield a
// generic c'all to deleted function' diagnostic instead.
Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted)
<< TemplateName;
NoteDeletedFunction(Best->Function);
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@
// This file implements semantic analysis for C++ lambda expressions.
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/SemaLambda.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include <optional>
Expand Down Expand Up @@ -1393,7 +1394,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,

// CUDA lambdas get implicit host and device attributes.
if (getLangOpts().CUDA)
CUDASetLambdaAttrs(Method);
CUDA().SetLambdaAttrs(Method);

// OpenMP lambdas might get assumumption attributes.
if (LangOpts.OpenMP)
Expand Down Expand Up @@ -2136,7 +2137,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
CaptureInits.push_back(Init.get());

if (LangOpts.CUDA)
CUDACheckLambdaCapture(CallOperator, From);
CUDA().CheckLambdaCapture(CallOperator, From);
}

Class->setCaptures(Context, Captures);
Expand Down
78 changes: 40 additions & 38 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/edit_distance.h"
Expand Down Expand Up @@ -3341,29 +3342,28 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
Functions.append(Operators.begin(), Operators.end());
}

Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
CXXSpecialMember SM,
bool ConstArg,
bool VolatileArg,
bool RValueThis,
bool ConstThis,
bool VolatileThis) {
Sema::SpecialMemberOverloadResult
Sema::LookupSpecialMember(CXXRecordDecl *RD, CXXSpecialMemberKind SM,
bool ConstArg, bool VolatileArg, bool RValueThis,
bool ConstThis, bool VolatileThis) {
assert(CanDeclareSpecialMemberFunction(RD) &&
"doing special member lookup into record that isn't fully complete");
RD = RD->getDefinition();
if (RValueThis || ConstThis || VolatileThis)
assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) &&
assert((SM == CXXSpecialMemberKind::CopyAssignment ||
SM == CXXSpecialMemberKind::MoveAssignment) &&
"constructors and destructors always have unqualified lvalue this");
if (ConstArg || VolatileArg)
assert((SM != CXXDefaultConstructor && SM != CXXDestructor) &&
assert((SM != CXXSpecialMemberKind::DefaultConstructor &&
SM != CXXSpecialMemberKind::Destructor) &&
"parameter-less special members can't have qualified arguments");

// FIXME: Get the caller to pass in a location for the lookup.
SourceLocation LookupLoc = RD->getLocation();

llvm::FoldingSetNodeID ID;
ID.AddPointer(RD);
ID.AddInteger(SM);
ID.AddInteger(llvm::to_underlying(SM));
ID.AddInteger(ConstArg);
ID.AddInteger(VolatileArg);
ID.AddInteger(RValueThis);
Expand All @@ -3382,7 +3382,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
Result = new (Result) SpecialMemberOverloadResultEntry(ID);
SpecialMemberCache.InsertNode(Result, InsertPoint);

if (SM == CXXDestructor) {
if (SM == CXXSpecialMemberKind::Destructor) {
if (RD->needsImplicitDestructor()) {
runWithSufficientStackSpace(RD->getLocation(), [&] {
DeclareImplicitDestructor(RD);
Expand All @@ -3406,7 +3406,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
QualType ArgType = CanTy;
ExprValueKind VK = VK_LValue;

if (SM == CXXDefaultConstructor) {
if (SM == CXXSpecialMemberKind::DefaultConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
NumArgs = 0;
if (RD->needsImplicitDefaultConstructor()) {
Expand All @@ -3415,7 +3415,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
});
}
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
if (SM == CXXSpecialMemberKind::CopyConstructor ||
SM == CXXSpecialMemberKind::MoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
if (RD->needsImplicitCopyConstructor()) {
runWithSufficientStackSpace(RD->getLocation(), [&] {
Expand Down Expand Up @@ -3453,15 +3454,16 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
// Possibly an XValue is actually correct in the case of move, but
// there is no semantic difference for class types in this restricted
// case.
if (SM == CXXCopyConstructor || SM == CXXCopyAssignment)
if (SM == CXXSpecialMemberKind::CopyConstructor ||
SM == CXXSpecialMemberKind::CopyAssignment)
VK = VK_LValue;
else
VK = VK_PRValue;
}

OpaqueValueExpr FakeArg(LookupLoc, ArgType, VK);

if (SM != CXXDefaultConstructor) {
if (SM != CXXSpecialMemberKind::DefaultConstructor) {
NumArgs = 1;
Arg = &FakeArg;
}
Expand All @@ -3487,7 +3489,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
// type, rather than because there's some other declared constructor.
// Every class has a copy/move constructor, copy/move assignment, and
// destructor.
assert(SM == CXXDefaultConstructor &&
assert(SM == CXXSpecialMemberKind::DefaultConstructor &&
"lookup for a constructor or assignment operator was empty");
Result->setMethod(nullptr);
Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted);
Expand All @@ -3505,7 +3507,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
DeclAccessPair Cand = DeclAccessPair::make(CandDecl, AS_public);
auto CtorInfo = getConstructorInfo(Cand);
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
if (SM == CXXSpecialMemberKind::CopyAssignment ||
SM == CXXSpecialMemberKind::MoveAssignment)
AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
llvm::ArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
Expand All @@ -3517,7 +3520,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
/*SuppressUserConversions*/ true);
} else if (FunctionTemplateDecl *Tmpl =
dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
if (SM == CXXSpecialMemberKind::CopyAssignment ||
SM == CXXSpecialMemberKind::MoveAssignment)
AddMethodTemplateCandidate(Tmpl, Cand, RD, nullptr, ThisTy,
Classification,
llvm::ArrayRef(&Arg, NumArgs), OCS, true);
Expand Down Expand Up @@ -3563,8 +3567,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
/// Look up the default constructor for the given class.
CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) {
SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false,
false, false);
LookupSpecialMember(Class, CXXSpecialMemberKind::DefaultConstructor,
false, false, false, false, false);

return cast_or_null<CXXConstructorDecl>(Result.getMethod());
}
Expand All @@ -3574,19 +3578,19 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class,
unsigned Quals) {
assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy ctor arg");
SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, false, false, false);
SpecialMemberOverloadResult Result = LookupSpecialMember(
Class, CXXSpecialMemberKind::CopyConstructor, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, false, false, false);

return cast_or_null<CXXConstructorDecl>(Result.getMethod());
}

/// Look up the moving constructor for the given class.
CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
unsigned Quals) {
SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXMoveConstructor, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, false, false, false);
SpecialMemberOverloadResult Result = LookupSpecialMember(
Class, CXXSpecialMemberKind::MoveConstructor, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, false, false, false);

return cast_or_null<CXXConstructorDecl>(Result.getMethod());
}
Expand Down Expand Up @@ -3618,11 +3622,10 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class,
"non-const, non-volatile qualifiers for copy assignment arg");
assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy assignment this");
SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXCopyAssignment, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, RValueThis,
ThisQuals & Qualifiers::Const,
ThisQuals & Qualifiers::Volatile);
SpecialMemberOverloadResult Result = LookupSpecialMember(
Class, CXXSpecialMemberKind::CopyAssignment, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const,
ThisQuals & Qualifiers::Volatile);

return Result.getMethod();
}
Expand All @@ -3634,11 +3637,10 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class,
unsigned ThisQuals) {
assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy assignment this");
SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXMoveAssignment, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, RValueThis,
ThisQuals & Qualifiers::Const,
ThisQuals & Qualifiers::Volatile);
SpecialMemberOverloadResult Result = LookupSpecialMember(
Class, CXXSpecialMemberKind::MoveAssignment, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const,
ThisQuals & Qualifiers::Volatile);

return Result.getMethod();
}
Expand All @@ -3651,8 +3653,8 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class,
/// \returns The destructor for this class.
CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
return cast_or_null<CXXDestructorDecl>(
LookupSpecialMember(Class, CXXDestructor, false, false, false, false,
false)
LookupSpecialMember(Class, CXXSpecialMemberKind::Destructor, false, false,
false, false, false)
.getMethod());
}

Expand Down
73 changes: 63 additions & 10 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,49 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
default:
return false;
}
case OpenACCClauseKind::If:
switch (DirectiveKind) {
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
case OpenACCDirectiveKind::Data:
case OpenACCDirectiveKind::EnterData:
case OpenACCDirectiveKind::ExitData:
case OpenACCDirectiveKind::HostData:
case OpenACCDirectiveKind::Init:
case OpenACCDirectiveKind::Shutdown:
case OpenACCDirectiveKind::Set:
case OpenACCDirectiveKind::Update:
case OpenACCDirectiveKind::Wait:
case OpenACCDirectiveKind::ParallelLoop:
case OpenACCDirectiveKind::SerialLoop:
case OpenACCDirectiveKind::KernelsLoop:
return true;
default:
return false;
}
default:
// Do nothing so we can go to the 'unimplemented' diagnostic instead.
return true;
}
llvm_unreachable("Invalid clause kind");
}

bool checkAlreadyHasClauseOfKind(
SemaOpenACC &S, ArrayRef<const OpenACCClause *> ExistingClauses,
SemaOpenACC::OpenACCParsedClause &Clause) {
const auto *Itr = llvm::find_if(ExistingClauses, [&](const OpenACCClause *C) {
return C->getClauseKind() == Clause.getClauseKind();
});
if (Itr != ExistingClauses.end()) {
S.Diag(Clause.getBeginLoc(), diag::err_acc_duplicate_clause_disallowed)
<< Clause.getDirectiveKind() << Clause.getClauseKind();
S.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
return true;
}
return false;
}

} // namespace

SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}
Expand Down Expand Up @@ -97,22 +134,38 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
// At most one 'default' clause may appear, and it must have a value of
// either 'none' or 'present'.
// Second half of the sentence is diagnosed during parsing.
auto Itr = llvm::find_if(ExistingClauses, [](const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Default;
});

if (Itr != ExistingClauses.end()) {
Diag(Clause.getBeginLoc(),
diag::err_acc_duplicate_clause_disallowed)
<< Clause.getDirectiveKind() << Clause.getClauseKind();
Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
return nullptr;
}

return OpenACCDefaultClause::Create(
getASTContext(), Clause.getDefaultClauseKind(), Clause.getBeginLoc(),
Clause.getLParenLoc(), Clause.getEndLoc());
}

case OpenACCClauseKind::If: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Parallel &&
Clause.getDirectiveKind() != OpenACCDirectiveKind::Serial &&
Clause.getDirectiveKind() != OpenACCDirectiveKind::Kernels)
break;

// There is no prose in the standard that says duplicates aren't allowed,
// but this diagnostic is present in other compilers, as well as makes
// sense.
if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
return nullptr;

// The parser has ensured that we have a proper condition expr, so there
// isn't really much to do here.

// TODO OpenACC: When we implement 'self', this clauses causes us to
// 'ignore' the self clause, so we should implement a warning here.
return OpenACCIfClause::Create(
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getConditionExpr(), Clause.getEndLoc());
}
default:
break;
}
Expand Down
166 changes: 101 additions & 65 deletions clang/lib/Sema/SemaOverload.cpp

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -4573,8 +4575,8 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,

// Exceptions aren't allowed in CUDA device code.
if (getLangOpts().CUDA)
CUDADiagIfDeviceCode(TryLoc, diag::err_cuda_device_exceptions)
<< "try" << CurrentCUDATarget();
CUDA().DiagIfDeviceCode(TryLoc, diag::err_cuda_device_exceptions)
<< "try" << llvm::to_underlying(CUDA().CurrentTarget());

if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try";
Expand Down
15 changes: 8 additions & 7 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
Expand Down Expand Up @@ -10155,9 +10156,9 @@ bool Sema::CheckFunctionTemplateSpecialization(
// take target attributes into account, we reject candidates
// here that have a different target.
if (LangOpts.CUDA &&
IdentifyCUDATarget(Specialization,
/* IgnoreImplicitHDAttr = */ true) !=
IdentifyCUDATarget(FD, /* IgnoreImplicitHDAttr = */ true)) {
CUDA().IdentifyTarget(Specialization,
/* IgnoreImplicitHDAttr = */ true) !=
CUDA().IdentifyTarget(FD, /* IgnoreImplicitHDAttr = */ true)) {
FailedCandidates.addCandidate().set(
I.getPair(), FunTmpl->getTemplatedDecl(),
MakeDeductionFailureInfo(
Expand Down Expand Up @@ -10328,7 +10329,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
// virtue e.g. of being constexpr, and it passes these implicit
// attributes on to its specializations.)
if (LangOpts.CUDA)
inheritCUDATargetAttrs(FD, *Specialization->getPrimaryTemplate());
CUDA().inheritTargetAttrs(FD, *Specialization->getPrimaryTemplate());

// The "previous declaration" for this function template specialization is
// the prior function template specialization.
Expand Down Expand Up @@ -11364,9 +11365,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// target attributes into account, we reject candidates here that
// have a different target.
if (LangOpts.CUDA &&
IdentifyCUDATarget(Specialization,
/* IgnoreImplicitHDAttr = */ true) !=
IdentifyCUDATarget(D.getDeclSpec().getAttributes())) {
CUDA().IdentifyTarget(Specialization,
/* IgnoreImplicitHDAttr = */ true) !=
CUDA().IdentifyTarget(D.getDeclSpec().getAttributes())) {
FailedCandidates.addCandidate().set(
P.getPair(), FunTmpl->getTemplatedDecl(),
MakeDeductionFailureInfo(
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
Expand Down Expand Up @@ -1142,7 +1143,8 @@ void Sema::PrintInstantiationStack() {
case CodeSynthesisContext::DeclaringSpecialMember:
Diags.Report(Active->PointOfInstantiation,
diag::note_in_declaration_of_implicit_special_member)
<< cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember;
<< cast<CXXRecordDecl>(Active->Entity)
<< llvm::to_underlying(Active->SpecialMember);
break;

case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
Expand All @@ -1160,7 +1162,8 @@ void Sema::PrintInstantiationStack() {
auto *MD = cast<CXXMethodDecl>(FD);
Diags.Report(Active->PointOfInstantiation,
diag::note_member_synthesized_at)
<< MD->isExplicitlyDefaulted() << DFK.asSpecialMember()
<< MD->isExplicitlyDefaulted()
<< llvm::to_underlying(DFK.asSpecialMember())
<< Context.getTagDeclType(MD->getParent());
} else if (DFK.isComparison()) {
QualType RecordType = FD->getParamDecl(0)
Expand Down
22 changes: 12 additions & 10 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
Expand Down Expand Up @@ -2438,7 +2439,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
return nullptr;
}
if (D->isDeleted())
SemaRef.SetDeclDeleted(Function, D->getLocation());
SemaRef.SetDeclDeleted(Function, D->getLocation(), D->getDeletedMessage());

NamedDecl *PrincipalDecl =
(TemplateParams ? cast<NamedDecl>(FunctionTemplate) : Function);
Expand Down Expand Up @@ -2814,7 +2815,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
}
if (D->isDeletedAsWritten())
SemaRef.SetDeclDeleted(Method, Method->getLocation());
SemaRef.SetDeclDeleted(Method, Method->getLocation(),
D->getDeletedMessage());

// If this is an explicit specialization, mark the implicitly-instantiated
// template specialization as being an explicit specialization too.
Expand Down Expand Up @@ -4866,7 +4868,7 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New,
FunctionDecl *Tmpl) {
// Transfer across any unqualified lookups.
if (auto *DFI = Tmpl->getDefaultedFunctionInfo()) {
if (auto *DFI = Tmpl->getDefalutedOrDeletedInfo()) {
SmallVector<DeclAccessPair, 32> Lookups;
Lookups.reserve(DFI->getUnqualifiedLookups().size());
bool AnyChanged = false;
Expand All @@ -4881,8 +4883,8 @@ bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New,

// It's unlikely that substitution will change any declarations. Don't
// store an unnecessary copy in that case.
New->setDefaultedFunctionInfo(
AnyChanged ? FunctionDecl::DefaultedFunctionInfo::Create(
New->setDefaultedOrDeletedInfo(
AnyChanged ? FunctionDecl::DefaultedOrDeletedFunctionInfo::Create(
SemaRef.Context, Lookups)
: DFI);
}
Expand Down Expand Up @@ -5123,10 +5125,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
assert(PatternDecl->isDefaulted() &&
"Special member needs to be defaulted");
auto PatternSM = getDefaultedFunctionKind(PatternDecl).asSpecialMember();
if (!(PatternSM == Sema::CXXCopyConstructor ||
PatternSM == Sema::CXXCopyAssignment ||
PatternSM == Sema::CXXMoveConstructor ||
PatternSM == Sema::CXXMoveAssignment))
if (!(PatternSM == CXXSpecialMemberKind::CopyConstructor ||
PatternSM == CXXSpecialMemberKind::CopyAssignment ||
PatternSM == CXXSpecialMemberKind::MoveConstructor ||
PatternSM == CXXSpecialMemberKind::MoveAssignment))
return;

auto *NewRec = dyn_cast<CXXRecordDecl>(Function->getDeclContext());
Expand Down Expand Up @@ -5537,7 +5539,7 @@ void Sema::InstantiateVariableInitializer(
}

if (getLangOpts().CUDA)
checkAllowedCUDAInitializer(Var);
CUDA().checkAllowedInitializer(Var);
}

/// Instantiate the definition of the given variable from its
Expand Down
42 changes: 22 additions & 20 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
Expand Down Expand Up @@ -376,11 +378,10 @@ enum TypeAttrLocation {
static void
processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL, const ParsedAttributesView &attrs,
Sema::CUDAFunctionTarget CFT = Sema::CFT_HostDevice);
CUDAFunctionTarget CFT = CUDAFunctionTarget::HostDevice);

static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
QualType &type,
Sema::CUDAFunctionTarget CFT);
QualType &type, CUDAFunctionTarget CFT);

static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &state,
ParsedAttr &attr, QualType &type);
Expand Down Expand Up @@ -627,7 +628,7 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state,
static bool distributeFunctionTypeAttrToInnermost(
TypeProcessingState &state, ParsedAttr &attr,
ParsedAttributesView &attrList, QualType &declSpecType,
Sema::CUDAFunctionTarget CFT) {
CUDAFunctionTarget CFT) {
Declarator &declarator = state.getDeclarator();

// Put it on the innermost function chunk, if there is one.
Expand All @@ -644,10 +645,10 @@ static bool distributeFunctionTypeAttrToInnermost(

/// A function type attribute was written in the decl spec. Try to
/// apply it somewhere.
static void
distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
ParsedAttr &attr, QualType &declSpecType,
Sema::CUDAFunctionTarget CFT) {
static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
ParsedAttr &attr,
QualType &declSpecType,
CUDAFunctionTarget CFT) {
state.saveDeclSpecAttrs();

// Try to distribute to the innermost.
Expand All @@ -664,9 +665,10 @@ distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
/// Try to apply it somewhere.
/// `Attrs` is the attribute list containing the declaration (either of the
/// declarator or the declaration).
static void distributeFunctionTypeAttrFromDeclarator(
TypeProcessingState &state, ParsedAttr &attr, QualType &declSpecType,
Sema::CUDAFunctionTarget CFT) {
static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
ParsedAttr &attr,
QualType &declSpecType,
CUDAFunctionTarget CFT) {
Declarator &declarator = state.getDeclarator();

// Try to distribute to the innermost.
Expand Down Expand Up @@ -694,7 +696,7 @@ static void distributeFunctionTypeAttrFromDeclarator(
/// declarator or the declaration).
static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
QualType &declSpecType,
Sema::CUDAFunctionTarget CFT) {
CUDAFunctionTarget CFT) {
// The called functions in this loop actually remove things from the current
// list, so iterating over the existing list isn't possible. Instead, make a
// non-owning copy and iterate over that.
Expand Down Expand Up @@ -2734,7 +2736,7 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM,
bool IsCUDADevice = (getLangOpts().CUDA && getLangOpts().CUDAIsDevice);
targetDiag(Loc,
IsCUDADevice ? diag::err_cuda_vla : diag::err_vla_unsupported)
<< (IsCUDADevice ? CurrentCUDATarget() : 0);
<< (IsCUDADevice ? llvm::to_underlying(CUDA().CurrentTarget()) : 0);
} else if (sema::FunctionScopeInfo *FSI = getCurFunction()) {
// VLAs are supported on this target, but we may need to do delayed
// checking that the VLA is not being used within a coroutine.
Expand Down Expand Up @@ -3617,7 +3619,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// D.getDeclarationAttributes()) because those are always C++11 attributes,
// and those don't get distributed.
distributeTypeAttrsFromDeclarator(
state, T, SemaRef.IdentifyCUDATarget(D.getAttributes()));
state, T, SemaRef.CUDA().IdentifyTarget(D.getAttributes()));

// Find the deduced type in this type. Look in the trailing return type if we
// have one, otherwise in the DeclSpec type.
Expand Down Expand Up @@ -4138,7 +4140,7 @@ static CallingConv getCCForDeclaratorChunk(
// handleFunctionTypeAttr.
CallingConv CC;
if (!S.CheckCallingConvAttr(AL, CC, /*FunctionDecl=*/nullptr,
S.IdentifyCUDATarget(D.getAttributes())) &&
S.CUDA().IdentifyTarget(D.getAttributes())) &&
(!FTI.isVariadic || supportsVariadicCall(CC))) {
return CC;
}
Expand Down Expand Up @@ -5824,7 +5826,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,

// See if there are any attributes on this declarator chunk.
processTypeAttrs(state, T, TAL_DeclChunk, DeclType.getAttrs(),
S.IdentifyCUDATarget(D.getAttributes()));
S.CUDA().IdentifyTarget(D.getAttributes()));

if (DeclType.Kind != DeclaratorChunk::Paren) {
if (ExpectNoDerefChunk && !IsNoDerefableChunk(DeclType))
Expand Down Expand Up @@ -8028,8 +8030,7 @@ static bool handleArmStateAttribute(Sema &S,
/// Process an individual function attribute. Returns true to
/// indicate that the attribute was handled, false if it wasn't.
static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
QualType &type,
Sema::CUDAFunctionTarget CFT) {
QualType &type, CUDAFunctionTarget CFT) {
Sema &S = state.getSema();

FunctionTypeUnwrapper unwrapped(S, type);
Expand Down Expand Up @@ -8863,7 +8864,7 @@ static void HandleHLSLParamModifierAttr(QualType &CurType,
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL,
const ParsedAttributesView &attrs,
Sema::CUDAFunctionTarget CFT) {
CUDAFunctionTarget CFT) {

state.setParsedNoDeref(false);
if (attrs.empty())
Expand Down Expand Up @@ -9738,7 +9739,8 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
: diag::note_non_literal_nontrivial_dtor)
<< RD;
if (!Dtor->isUserProvided())
SpecialMemberIsTrivial(Dtor, CXXDestructor, TAH_IgnoreTrivialABI,
SpecialMemberIsTrivial(Dtor, CXXSpecialMemberKind::Destructor,
TAH_IgnoreTrivialABI,
/*Diagnose*/ true);
}
}
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -11103,6 +11103,20 @@ OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause(
ParsedClause.setDefaultDetails(
cast<OpenACCDefaultClause>(OldClause)->getDefaultClauseKind());
break;
case OpenACCClauseKind::If: {
Expr *Cond = const_cast<Expr *>(
cast<OpenACCIfClause>(OldClause)->getConditionExpr());
assert(Cond && "If constructed with invalid Condition");
Sema::ConditionResult Res =
TransformCondition(Cond->getExprLoc(), /*Var=*/nullptr, Cond,
Sema::ConditionKind::Boolean);

if (Res.isInvalid() || !Res.get().second)
return nullptr;

ParsedClause.setConditionDetails(Res.get().second);
break;
}
default:
assert(false && "Unhandled OpenACC clause in TreeTransform");
return nullptr;
Expand Down
35 changes: 32 additions & 3 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/Weak.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ASTDeserializationListener.h"
Expand Down Expand Up @@ -3795,6 +3796,29 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
}
break;

case DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD: {
if (Record.size() % 3 != 0)
return llvm::createStringError(
std::errc::illegal_byte_sequence,
"invalid DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD block in AST "
"file");
for (unsigned I = 0, N = Record.size(); I != N; I += 3) {
GlobalDeclID ID = getGlobalDeclID(F, Record[I]);

uint64_t BaseOffset = F.DeclsBlockStartOffset;
assert(BaseOffset && "Invalid DeclsBlockStartOffset for module file!");
uint64_t LexicalOffset = Record[I + 1] ? BaseOffset + Record[I + 1] : 0;
uint64_t VisibleOffset = Record[I + 2] ? BaseOffset + Record[I + 2] : 0;

DelayedNamespaceOffsetMap[ID] = {LexicalOffset, VisibleOffset};

assert(!GetExistingDecl(ID) &&
"We shouldn't load the namespace in the front of delayed "
"namespace lexical and visible block");
}
break;
}

case OBJC_CATEGORIES_MAP:
if (F.LocalNumObjCCategoriesInMap != 0)
return llvm::createStringError(
Expand Down Expand Up @@ -3972,7 +3996,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
if (Record.size() != 1)
return llvm::createStringError(std::errc::illegal_byte_sequence,
"invalid cuda pragma options record");
ForceCUDAHostDeviceDepth = Record[0];
ForceHostDeviceDepth = Record[0];
break;

case ALIGN_PACK_PRAGMA_OPTIONS: {
Expand Down Expand Up @@ -8251,7 +8275,7 @@ void ASTReader::UpdateSema() {
PragmaMSPointersToMembersState,
PointersToMembersPragmaLocation);
}
SemaObj->ForceCUDAHostDeviceDepth = ForceCUDAHostDeviceDepth;
SemaObj->CUDA().ForceHostDeviceDepth = ForceHostDeviceDepth;

if (PragmaAlignPackCurrentValue) {
// The bottom of the stack might have a default value. It must be adjusted
Expand Down Expand Up @@ -11764,6 +11788,12 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
return OpenACCDefaultClause::Create(getContext(), DCK, BeginLoc, LParenLoc,
EndLoc);
}
case OpenACCClauseKind::If: {
SourceLocation LParenLoc = readSourceLocation();
Expr *CondExpr = readSubExpr();
return OpenACCIfClause::Create(getContext(), BeginLoc, LParenLoc, CondExpr,
EndLoc);
}
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
Expand All @@ -11772,7 +11802,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
case OpenACCClauseKind::Worker:
case OpenACCClauseKind::Vector:
case OpenACCClauseKind::NoHost:
case OpenACCClauseKind::If:
case OpenACCClauseKind::Self:
case OpenACCClauseKind::Copy:
case OpenACCClauseKind::UseDevice:
Expand Down
27 changes: 23 additions & 4 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1103,16 +1103,26 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setHasODRHash(true);
}

if (FD->isDefaulted()) {
if (unsigned NumLookups = Record.readInt()) {
if (FD->isDefaulted() || FD->isDeletedAsWritten()) {
// If 'Info' is nonzero, we need to read an DefaultedOrDeletedInfo; if,
// additionally, the second bit is also set, we also need to read
// a DeletedMessage for the DefaultedOrDeletedInfo.
if (auto Info = Record.readInt()) {
bool HasMessage = Info & 2;
StringLiteral *DeletedMessage =
HasMessage ? cast<StringLiteral>(Record.readExpr()) : nullptr;

unsigned NumLookups = Record.readInt();
SmallVector<DeclAccessPair, 8> Lookups;
for (unsigned I = 0; I != NumLookups; ++I) {
NamedDecl *ND = Record.readDeclAs<NamedDecl>();
AccessSpecifier AS = (AccessSpecifier)Record.readInt();
Lookups.push_back(DeclAccessPair::make(ND, AS));
}
FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create(
Reader.getContext(), Lookups));

FD->setDefaultedOrDeletedInfo(
FunctionDecl::DefaultedOrDeletedFunctionInfo::Create(
Reader.getContext(), Lookups, DeletedMessage));
}
}

Expand Down Expand Up @@ -4125,6 +4135,15 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// offsets for its tables of lexical and visible declarations.
if (auto *DC = dyn_cast<DeclContext>(D)) {
std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);

// Get the lexical and visible block for the delayed namespace.
// It is sufficient to judge if ID is in DelayedNamespaceOffsetMap.
// But it may be more efficient to filter the other cases.
if (!Offsets.first && !Offsets.second && isa<NamespaceDecl>(D))
if (auto Iter = DelayedNamespaceOffsetMap.find(ID);
Iter != DelayedNamespaceOffsetMap.end())
Offsets = Iter->second;

if (Offsets.first &&
ReadLexicalDeclContextStorage(*Loc.F, DeclsCursor, Offsets.first, DC))
return nullptr;
Expand Down
151 changes: 126 additions & 25 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
#include "clang/Sema/IdentifierResolver.h"
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/Weak.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ASTReader.h"
Expand Down Expand Up @@ -869,6 +870,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
RECORD(UPDATE_VISIBLE);
RECORD(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD);
RECORD(DECL_UPDATE_OFFSETS);
RECORD(DECL_UPDATES);
RECORD(CUDA_SPECIAL_DECL_REFS);
Expand Down Expand Up @@ -3026,10 +3028,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record, CM);
}

// Emit the initializers, if any.
// Emit the reachable initializers.
// The initializer may only be unreachable in reduced BMI.
RecordData Inits;
for (Decl *D : Context->getModuleInitializers(Mod))
Inits.push_back(GetDeclRef(D));
if (wasDeclEmitted(D))
Inits.push_back(GetDeclRef(D));
if (!Inits.empty())
Stream.EmitRecord(SUBMODULE_INITIALIZERS, Inits);

Expand Down Expand Up @@ -3208,6 +3212,9 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
uint64_t Offset = Stream.GetCurrentBitNo();
SmallVector<uint32_t, 128> KindDeclPairs;
for (const auto *D : DC->decls()) {
if (DoneWritingDeclsAndTypes && !wasDeclEmitted(D))
continue;

KindDeclPairs.push_back(D->getKind());
KindDeclPairs.push_back(GetDeclRef(D));
}
Expand Down Expand Up @@ -3862,8 +3869,14 @@ class ASTDeclContextNameLookupTrait {
data_type getData(const Coll &Decls) {
unsigned Start = DeclIDs.size();
for (NamedDecl *D : Decls) {
DeclIDs.push_back(
Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), D)));
NamedDecl *DeclForLocalLookup =
getDeclForLocalLookup(Writer.getLangOpts(), D);

if (Writer.getDoneWritingDeclsAndTypes() &&
!Writer.wasDeclEmitted(DeclForLocalLookup))
continue;

DeclIDs.push_back(Writer.GetDeclRef(DeclForLocalLookup));
}
return std::make_pair(Start, DeclIDs.size());
}
Expand Down Expand Up @@ -3972,11 +3985,20 @@ bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
DC->hasNeedToReconcileExternalVisibleStorage();
}

bool ASTWriter::isLookupResultEntirelyExternal(StoredDeclsList &Result,
DeclContext *DC) {
for (auto *D : Result.getLookupResult())
if (!getDeclForLocalLookup(getLangOpts(), D)->isFromASTFile())
return false;
bool ASTWriter::isLookupResultEntirelyExternalOrUnreachable(
StoredDeclsList &Result, DeclContext *DC) {
for (auto *D : Result.getLookupResult()) {
auto *LocalD = getDeclForLocalLookup(getLangOpts(), D);
if (LocalD->isFromASTFile())
continue;

// We can only be sure whether the local declaration is reachable
// after we done writing the declarations and types.
if (DoneWritingDeclsAndTypes && !wasDeclEmitted(LocalD))
continue;

return false;
}

return true;
}
Expand Down Expand Up @@ -4014,8 +4036,17 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
// don't need to write an entry for the name at all. If we can't
// write out a lookup set without performing more deserialization,
// just skip this entry.
if (isLookupResultExternal(Result, DC) &&
isLookupResultEntirelyExternal(Result, DC))
//
// Also in reduced BMI, we'd like to avoid writing unreachable
// declarations in GMF, so we need to avoid writing declarations
// that entirely external or unreachable.
//
// FIMXE: It looks sufficient to test
// isLookupResultEntirelyExternalOrUnreachable here. But due to bug we have
// to test isLookupResultExternal here. See
// https://github.com/llvm/llvm-project/issues/61065 for details.
if ((GeneratingReducedBMI || isLookupResultExternal(Result, DC)) &&
isLookupResultEntirelyExternalOrUnreachable(Result, DC))
continue;

// We also skip empty results. If any of the results could be external and
Expand Down Expand Up @@ -4206,9 +4237,15 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
continue;
}

for (NamedDecl *ND : Result)
if (!ND->isFromASTFile())
GetDeclRef(ND);
for (NamedDecl *ND : Result) {
if (ND->isFromASTFile())
continue;

if (DoneWritingDeclsAndTypes && !wasDeclEmitted(ND))
continue;

GetDeclRef(ND);
}
}

return 0;
Expand Down Expand Up @@ -4299,8 +4336,8 @@ void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) {
Stream.EmitRecord(OPENCL_EXTENSIONS, Record);
}
void ASTWriter::WriteCUDAPragmas(Sema &SemaRef) {
if (SemaRef.ForceCUDAHostDeviceDepth > 0) {
RecordData::value_type Record[] = {SemaRef.ForceCUDAHostDeviceDepth};
if (SemaRef.CUDA().ForceHostDeviceDepth > 0) {
RecordData::value_type Record[] = {SemaRef.CUDA().ForceHostDeviceDepth};
Stream.EmitRecord(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH, Record);
}
}
Expand Down Expand Up @@ -4976,9 +5013,18 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();

// Force all top level declarations to be emitted.
for (const auto *D : TU->noload_decls())
if (!D->isFromASTFile())
GetDeclRef(D);
//
// We start emitting top level declarations from the module purview to
// implement the eliding unreachable declaration feature.
for (const auto *D : TU->noload_decls()) {
if (D->isFromASTFile())
continue;

if (GeneratingReducedBMI && D->isFromExplicitGlobalModule())
continue;

GetDeclRef(D);
}

// If the translation unit has an anonymous namespace, and we don't already
// have an update block for it, write it as an update block.
Expand Down Expand Up @@ -5288,24 +5334,59 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
WriteDecl(Context, DOT.getDecl());
}
} while (!DeclUpdates.empty());
Stream.ExitBlock();

DoneWritingDeclsAndTypes = true;

// DelayedNamespace is only meaningful in reduced BMI.
// See the comments of DelayedNamespace for details.
assert(DelayedNamespace.empty() || GeneratingReducedBMI);
RecordData DelayedNamespaceRecord;
for (NamespaceDecl *NS : DelayedNamespace) {
uint64_t LexicalOffset = WriteDeclContextLexicalBlock(Context, NS);
uint64_t VisibleOffset = WriteDeclContextVisibleBlock(Context, NS);

// Write the offset relative to current block.
if (LexicalOffset)
LexicalOffset -= DeclTypesBlockStartOffset;

if (VisibleOffset)
VisibleOffset -= DeclTypesBlockStartOffset;

DelayedNamespaceRecord.push_back(getDeclID(NS));
DelayedNamespaceRecord.push_back(LexicalOffset);
DelayedNamespaceRecord.push_back(VisibleOffset);
}

// The process of writing lexical and visible block for delayed namespace
// shouldn't introduce any new decls, types or update to emit.
assert(DeclTypesToEmit.empty());
assert(DeclUpdates.empty());

Stream.ExitBlock();

// These things can only be done once we've written out decls and types.
WriteTypeDeclOffsets();
if (!DeclUpdatesOffsetsRecord.empty())
Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord);

if (!DelayedNamespaceRecord.empty())
Stream.EmitRecord(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD,
DelayedNamespaceRecord);

const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
SmallVector<uint32_t, 128> NewGlobalKindDeclPairs;
for (const auto *D : TU->noload_decls()) {
if (!D->isFromASTFile()) {
NewGlobalKindDeclPairs.push_back(D->getKind());
NewGlobalKindDeclPairs.push_back(GetDeclRef(D));
}
if (D->isFromASTFile())
continue;

// In reduced BMI, skip unreached declarations.
if (!wasDeclEmitted(D))
continue;

NewGlobalKindDeclPairs.push_back(D->getKind());
NewGlobalKindDeclPairs.push_back(GetDeclRef(D));
}

auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
Expand Down Expand Up @@ -5814,6 +5895,21 @@ DeclID ASTWriter::getDeclID(const Decl *D) {
return DeclIDs[D];
}

bool ASTWriter::wasDeclEmitted(const Decl *D) const {
assert(D);

assert(DoneWritingDeclsAndTypes &&
"wasDeclEmitted should only be called after writing declarations");

if (D->isFromASTFile())
return true;

bool Emitted = DeclIDs.contains(D);
assert((Emitted || GeneratingReducedBMI) &&
"The declaration can only be omitted in reduced BMI.");
return Emitted;
}

void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
assert(ID);
assert(D);
Expand Down Expand Up @@ -7422,6 +7518,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
writeEnum(DC->getDefaultClauseKind());
return;
}
case OpenACCClauseKind::If: {
const auto *IC = cast<OpenACCIfClause>(C);
writeSourceLocation(IC->getLParenLoc());
AddStmt(const_cast<Expr *>(IC->getConditionExpr()));
return;
}
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
Expand All @@ -7430,7 +7532,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::Worker:
case OpenACCClauseKind::Vector:
case OpenACCClauseKind::NoHost:
case OpenACCClauseKind::If:
case OpenACCClauseKind::Self:
case OpenACCClauseKind::Copy:
case OpenACCClauseKind::UseDevice:
Expand Down
38 changes: 34 additions & 4 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -749,8 +749,15 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
if (!ShouldSkipCheckingODR)
Record.push_back(D->getODRHash());

if (D->isDefaulted()) {
if (auto *FDI = D->getDefaultedFunctionInfo()) {
if (D->isDefaulted() || D->isDeletedAsWritten()) {
if (auto *FDI = D->getDefalutedOrDeletedInfo()) {
// Store both that there is an DefaultedOrDeletedInfo and whether it
// contains a DeletedMessage.
StringLiteral *DeletedMessage = FDI->getDeletedMessage();
Record.push_back(1 | (DeletedMessage ? 2 : 0));
if (DeletedMessage)
Record.AddStmt(DeletedMessage);

Record.push_back(FDI->getUnqualifiedLookups().size());
for (DeclAccessPair P : FDI->getUnqualifiedLookups()) {
Record.AddDeclRef(P.getDecl());
Expand Down Expand Up @@ -1719,6 +1726,15 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {

if (D->isFirstDecl())
AddTemplateSpecializations(D);

// Force emitting the corresponding deduction guide in reduced BMI mode.
// Otherwise, the deduction guide may be optimized out incorrectly.
if (Writer.isGeneratingReducedBMI()) {
auto Name = Context.DeclarationNames.getCXXDeductionGuideName(D);
for (auto *DG : D->getDeclContext()->noload_lookup(Name))
Writer.GetDeclRef(DG);
}

Code = serialization::DECL_CLASS_TEMPLATE;
}

Expand Down Expand Up @@ -1963,8 +1979,22 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC) {
"You need to update the serializer after you change the "
"DeclContextBits");

Record.AddOffset(Writer.WriteDeclContextLexicalBlock(Context, DC));
Record.AddOffset(Writer.WriteDeclContextVisibleBlock(Context, DC));
uint64_t LexicalOffset = 0;
uint64_t VisibleOffset = 0;

if (Writer.isGeneratingReducedBMI() && isa<NamespaceDecl>(DC) &&
cast<NamespaceDecl>(DC)->isFromExplicitGlobalModule()) {
// In reduced BMI, delay writing lexical and visible block for namespace
// in the global module fragment. See the comments of DelayedNamespace for
// details.
Writer.DelayedNamespace.push_back(cast<NamespaceDecl>(DC));
} else {
LexicalOffset = Writer.WriteDeclContextLexicalBlock(Context, DC);
VisibleOffset = Writer.WriteDeclContextVisibleBlock(Context, DC);
}

Record.AddOffset(LexicalOffset);
Record.AddOffset(VisibleOffset);
}

const Decl *ASTWriter::getFirstLocalDecl(const Decl *D) {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,10 @@ const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
Type = RefT->getPointeeType();
}

if (const auto *PtrT = Type->getAs<PointerType>()) {
Type = PtrT->getPointeeType();
}

return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ SVal ExprEngine::computeObjectUnderConstruction(
// We are on the top frame of the analysis. We do not know where is the
// object returned to. Conjure a symbolic region for the return value.
// TODO: We probably need a new MemRegion kind to represent the storage
// of that SymbolicRegion, so that we cound produce a fancy symbol
// of that SymbolicRegion, so that we could produce a fancy symbol
// instead of an anonymous conjured symbol.
// TODO: Do we need to track the region to avoid having it dead
// too early? It does die too early, at least in C++17, but because
Expand Down
161 changes: 135 additions & 26 deletions clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ DependencyScanningFilesystemSharedCache::CacheShard::findEntryByFilename(
StringRef Filename) const {
assert(llvm::sys::path::is_absolute_gnu(Filename));
std::lock_guard<std::mutex> LockGuard(CacheLock);
auto It = EntriesByFilename.find(Filename);
return It == EntriesByFilename.end() ? nullptr : It->getValue();
auto It = CacheByFilename.find(Filename);
return It == CacheByFilename.end() ? nullptr : It->getValue().first;
}

const CachedFileSystemEntry *
Expand All @@ -130,36 +130,75 @@ DependencyScanningFilesystemSharedCache::CacheShard::
getOrEmplaceEntryForFilename(StringRef Filename,
llvm::ErrorOr<llvm::vfs::Status> Stat) {
std::lock_guard<std::mutex> LockGuard(CacheLock);
auto Insertion = EntriesByFilename.insert({Filename, nullptr});
if (Insertion.second)
Insertion.first->second =
auto [It, Inserted] = CacheByFilename.insert({Filename, {nullptr, nullptr}});
auto &[CachedEntry, CachedRealPath] = It->getValue();
if (!CachedEntry) {
// The entry is not present in the shared cache. Either the cache doesn't
// know about the file at all, or it only knows about its real path.
assert((Inserted || CachedRealPath) && "existing file with empty pair");
CachedEntry =
new (EntryStorage.Allocate()) CachedFileSystemEntry(std::move(Stat));
return *Insertion.first->second;
}
return *CachedEntry;
}

const CachedFileSystemEntry &
DependencyScanningFilesystemSharedCache::CacheShard::getOrEmplaceEntryForUID(
llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat,
std::unique_ptr<llvm::MemoryBuffer> Contents) {
std::lock_guard<std::mutex> LockGuard(CacheLock);
auto Insertion = EntriesByUID.insert({UID, nullptr});
if (Insertion.second) {
auto [It, Inserted] = EntriesByUID.insert({UID, nullptr});
auto &CachedEntry = It->getSecond();
if (Inserted) {
CachedFileContents *StoredContents = nullptr;
if (Contents)
StoredContents = new (ContentsStorage.Allocate())
CachedFileContents(std::move(Contents));
Insertion.first->second = new (EntryStorage.Allocate())
CachedEntry = new (EntryStorage.Allocate())
CachedFileSystemEntry(std::move(Stat), StoredContents);
}
return *Insertion.first->second;
return *CachedEntry;
}

const CachedFileSystemEntry &
DependencyScanningFilesystemSharedCache::CacheShard::
getOrInsertEntryForFilename(StringRef Filename,
const CachedFileSystemEntry &Entry) {
std::lock_guard<std::mutex> LockGuard(CacheLock);
return *EntriesByFilename.insert({Filename, &Entry}).first->getValue();
auto [It, Inserted] = CacheByFilename.insert({Filename, {&Entry, nullptr}});
auto &[CachedEntry, CachedRealPath] = It->getValue();
if (!Inserted || !CachedEntry)
CachedEntry = &Entry;
return *CachedEntry;
}

const CachedRealPath *
DependencyScanningFilesystemSharedCache::CacheShard::findRealPathByFilename(
StringRef Filename) const {
assert(llvm::sys::path::is_absolute_gnu(Filename));
std::lock_guard<std::mutex> LockGuard(CacheLock);
auto It = CacheByFilename.find(Filename);
return It == CacheByFilename.end() ? nullptr : It->getValue().second;
}

const CachedRealPath &DependencyScanningFilesystemSharedCache::CacheShard::
getOrEmplaceRealPathForFilename(StringRef Filename,
llvm::ErrorOr<llvm::StringRef> RealPath) {
std::lock_guard<std::mutex> LockGuard(CacheLock);

const CachedRealPath *&StoredRealPath = CacheByFilename[Filename].second;
if (!StoredRealPath) {
auto OwnedRealPath = [&]() -> CachedRealPath {
if (!RealPath)
return RealPath.getError();
return RealPath->str();
}();

StoredRealPath = new (RealPathStorage.Allocate())
CachedRealPath(std::move(OwnedRealPath));
}

return *StoredRealPath;
}

static bool shouldCacheStatFailures(StringRef Filename) {
Expand Down Expand Up @@ -233,24 +272,15 @@ DependencyScanningWorkerFilesystem::computeAndStoreResult(
llvm::ErrorOr<EntryRef>
DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
StringRef OriginalFilename) {
StringRef FilenameForLookup;
SmallString<256> PathBuf;
if (llvm::sys::path::is_absolute_gnu(OriginalFilename)) {
FilenameForLookup = OriginalFilename;
} else if (!WorkingDirForCacheLookup) {
return WorkingDirForCacheLookup.getError();
} else {
StringRef RelFilename = OriginalFilename;
RelFilename.consume_front("./");
PathBuf = *WorkingDirForCacheLookup;
llvm::sys::path::append(PathBuf, RelFilename);
FilenameForLookup = PathBuf.str();
}
assert(llvm::sys::path::is_absolute_gnu(FilenameForLookup));
auto FilenameForLookup = tryGetFilenameForLookup(OriginalFilename, PathBuf);
if (!FilenameForLookup)
return FilenameForLookup.getError();

if (const auto *Entry =
findEntryByFilenameWithWriteThrough(FilenameForLookup))
findEntryByFilenameWithWriteThrough(*FilenameForLookup))
return EntryRef(OriginalFilename, *Entry).unwrapError();
auto MaybeEntry = computeAndStoreResult(OriginalFilename, FilenameForLookup);
auto MaybeEntry = computeAndStoreResult(OriginalFilename, *FilenameForLookup);
if (!MaybeEntry)
return MaybeEntry.getError();
return EntryRef(OriginalFilename, *MaybeEntry).unwrapError();
Expand All @@ -270,6 +300,17 @@ DependencyScanningWorkerFilesystem::status(const Twine &Path) {
return Result->getStatus();
}

bool DependencyScanningWorkerFilesystem::exists(const Twine &Path) {
// While some VFS overlay filesystems may implement more-efficient
// mechanisms for `exists` queries, `DependencyScanningWorkerFilesystem`
// typically wraps `RealFileSystem` which does not specialize `exists`,
// so it is not likely to benefit from such optimizations. Instead,
// it is more-valuable to have this query go through the
// cached-`status` code-path of the `DependencyScanningWorkerFilesystem`.
llvm::ErrorOr<llvm::vfs::Status> Status = status(Path);
return Status && Status->exists();
}

namespace {

/// The VFS that is used by clang consumes the \c CachedFileSystemEntry using
Expand Down Expand Up @@ -330,6 +371,54 @@ DependencyScanningWorkerFilesystem::openFileForRead(const Twine &Path) {
return DepScanFile::create(Result.get());
}

std::error_code
DependencyScanningWorkerFilesystem::getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) {
SmallString<256> OwnedFilename;
StringRef OriginalFilename = Path.toStringRef(OwnedFilename);

SmallString<256> PathBuf;
auto FilenameForLookup = tryGetFilenameForLookup(OriginalFilename, PathBuf);
if (!FilenameForLookup)
return FilenameForLookup.getError();

auto HandleCachedRealPath =
[&Output](const CachedRealPath &RealPath) -> std::error_code {
if (!RealPath)
return RealPath.getError();
Output.assign(RealPath->begin(), RealPath->end());
return {};
};

// If we already have the result in local cache, no work required.
if (const auto *RealPath =
LocalCache.findRealPathByFilename(*FilenameForLookup))
return HandleCachedRealPath(*RealPath);

// If we have the result in the shared cache, cache it locally.
auto &Shard = SharedCache.getShardForFilename(*FilenameForLookup);
if (const auto *ShardRealPath =
Shard.findRealPathByFilename(*FilenameForLookup)) {
const auto &RealPath = LocalCache.insertRealPathForFilename(
*FilenameForLookup, *ShardRealPath);
return HandleCachedRealPath(RealPath);
}

// If we don't know the real path, compute it...
std::error_code EC = getUnderlyingFS().getRealPath(OriginalFilename, Output);
llvm::ErrorOr<llvm::StringRef> ComputedRealPath = EC;
if (!EC)
ComputedRealPath = StringRef{Output.data(), Output.size()};

// ...and try to write it into the shared cache. In case some other thread won
// this race and already wrote its own result there, just adopt it. Write
// whatever is in the shared cache into the local one.
const auto &RealPath = Shard.getOrEmplaceRealPathForFilename(
*FilenameForLookup, ComputedRealPath);
return HandleCachedRealPath(
LocalCache.insertRealPathForFilename(*FilenameForLookup, RealPath));
}

std::error_code DependencyScanningWorkerFilesystem::setCurrentWorkingDirectory(
const Twine &Path) {
std::error_code EC = ProxyFileSystem::setCurrentWorkingDirectory(Path);
Expand All @@ -351,4 +440,24 @@ void DependencyScanningWorkerFilesystem::updateWorkingDirForCacheLookup() {
llvm::sys::path::is_absolute_gnu(*WorkingDirForCacheLookup));
}

llvm::ErrorOr<StringRef>
DependencyScanningWorkerFilesystem::tryGetFilenameForLookup(
StringRef OriginalFilename, llvm::SmallVectorImpl<char> &PathBuf) const {
StringRef FilenameForLookup;
if (llvm::sys::path::is_absolute_gnu(OriginalFilename)) {
FilenameForLookup = OriginalFilename;
} else if (!WorkingDirForCacheLookup) {
return WorkingDirForCacheLookup.getError();
} else {
StringRef RelFilename = OriginalFilename;
RelFilename.consume_front("./");
PathBuf.assign(WorkingDirForCacheLookup->begin(),
WorkingDirForCacheLookup->end());
llvm::sys::path::append(PathBuf, RelFilename);
FilenameForLookup = StringRef{PathBuf.begin(), PathBuf.size()};
}
assert(llvm::sys::path::is_absolute_gnu(FilenameForLookup));
return FilenameForLookup;
}

const char DependencyScanningWorkerFilesystem::ID = 0;
10 changes: 8 additions & 2 deletions clang/test/AST/Interp/c.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 -Wcast-qual %s
// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic-expected,all -std=c11 -Wcast-qual %s
// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic,pedantic-expected,all -std=c11 -Wcast-qual %s
// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 -Wcast-qual %s
// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic-ref,all -std=c11 -Wcast-qual %s
// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic,pedantic-ref,all -std=c11 -Wcast-qual %s

typedef __INTPTR_TYPE__ intptr_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
Expand Down Expand Up @@ -227,3 +227,9 @@ int castViaInt[*(int*)(unsigned long)"test"]; // ref-error {{variable length arr
// pedantic-ref-error {{variable length array}} \
// expected-error {{variable length array}} \
// pedantic-expected-error {{variable length array}}

const void (*const funcp)(void) = (void*)123; // pedantic-warning {{converts between void pointer and function pointer}}
_Static_assert(funcp == (void*)0, ""); // all-error {{failed due to requirement 'funcp == (void *)0'}} \
// pedantic-warning {{expression is not an integer constant expression}}
_Static_assert(funcp == (void*)123, ""); // pedantic-warning {{equality comparison between function pointer and void pointer}} \
// pedantic-warning {{expression is not an integer constant expression}}
23 changes: 23 additions & 0 deletions clang/test/AST/ast-dump-cxx2c-delete-with-message.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Without serialization:
// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
//
// With serialization:
// RUN: %clang_cc1 -emit-pch -o %t %s
// RUN: %clang_cc1 -x c++ -include-pch %t -ast-dump-all /dev/null | FileCheck %s

struct S {
// CHECK: CXXMethodDecl {{.*}} a 'void ()' delete
// CHECK-NEXT: delete message: StringLiteral {{.*}} "foo"
void a() = delete("foo");

// CHECK: FunctionTemplateDecl {{.*}} b
// CHECK-NEXT: TemplateTypeParmDecl
// CHECK-NEXT: CXXMethodDecl {{.*}} b 'void ()' delete
// CHECK-NEXT: delete message: StringLiteral {{.*}} "bar"
template <typename>
void b() = delete("bar");
};

// CHECK: FunctionDecl {{.*}} c 'void ()' delete
// CHECK-NEXT: delete message: StringLiteral {{.*}} "baz"
void c() = delete("baz");
Loading