Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions clang/include/clang/Sema/SemaSYCL.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ class SemaSYCL : public SemaBase {
// special types inside. Relevant for free function kernels only.
llvm::DenseSet<const RecordDecl *> StructsWithSpecialTypes;

llvm::DenseSet<CanonicalDeclPtr<const TagDecl>> DeepTypeCheckedRecords;

public:
SemaSYCL(Sema &S);

Expand Down Expand Up @@ -319,9 +321,7 @@ class SemaSYCL : public SemaBase {
DeviceDiagnosticReason Reason = DeviceDiagnosticReason::Sycl |
DeviceDiagnosticReason::Esimd);

void deepTypeCheckForDevice(SourceLocation UsedAt,
llvm::DenseSet<QualType> Visited,
ValueDecl *DeclToCheck);
void deepTypeCheckForDevice(SourceLocation UsedAt, ValueDecl *DeclToCheck);

const KernelFDPairs &getKernelFDPairs() { return SyclKernelsToOpenCLKernels; }

Expand Down
6 changes: 2 additions & 4 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2438,10 +2438,8 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
// declarations can be replaced with an array of bytes of the same size during
// codegen, such replacement doesn't seem to be possible for types without
// constant byte size like zero length arrays. So, do a deep check for SYCL.
if (D && LangOpts.SYCLIsDevice) {
llvm::DenseSet<QualType> Visited;
SYCL().deepTypeCheckForDevice(Loc, Visited, D);
}
if (D && LangOpts.SYCLIsDevice)
SYCL().deepTypeCheckForDevice(Loc, D);

Decl *C = cast<Decl>(getCurLexicalContext());

Expand Down
47 changes: 45 additions & 2 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,21 @@ static bool isZeroSizedArray(SemaSYCL &S, QualType Ty) {
return false;
}

static std::pair<const RecordDecl *, bool> needsDeepTypeCheck(SemaSYCL &S,
QualType Ty) {
while (Ty->isAnyPointerType() || Ty->isArrayType() || Ty->isReferenceType()) {
// A zero-length array has no record to traverse, but the DFS below must
// still visit it to emit the required diagnostic.
if (isZeroSizedArray(S, Ty))
return {nullptr, true};
if (Ty->isArrayType())
Ty = QualType{Ty->getArrayElementTypeNoTypeQual(), 0};
Comment thread
tahonermann marked this conversation as resolved.
else
Ty = Ty->getPointeeType();
}
return {Ty->getAsRecordDecl(), false};
}

static void checkSYCLType(SemaSYCL &S, QualType Ty, SourceRange Loc,
llvm::DenseSet<QualType> Visited,
SourceRange UsedAtLoc = SourceRange()) {
Expand Down Expand Up @@ -5986,13 +6001,25 @@ SemaSYCL::DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID,
}

void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt,
llvm::DenseSet<QualType> Visited,
ValueDecl *DeclToCheck) {
assert(getLangOpts().SYCLIsDevice &&
"Should only be called during SYCL compilation");
const auto [RootRecord, HasZeroSizedArray] =
needsDeepTypeCheck(*this, DeclToCheck->getType());
if (!RootRecord && !HasZeroSizedArray)
return;
if (RootRecord && RootRecord->isCompleteDefinition() &&
DeepTypeCheckedRecords.contains(RootRecord))
return;

// Emit notes only for the first discovered declaration of unsupported type
// to avoid mess of notes. This flag is to track that error already happened.
bool NeedToEmitNotes = true;
bool FoundError = false;
bool CanCacheResult = RootRecord && RootRecord->isCompleteDefinition();
llvm::SmallDenseSet<QualType, 8> Visited;
// Cache complete nested records after this whole traversal succeeds.
llvm::SmallDenseSet<CanonicalDeclPtr<const TagDecl>, 8> VisitedRecords;

auto Check = [&](QualType TypeToCheck, const ValueDecl *D) {
bool ErrorFound = false;
Expand Down Expand Up @@ -6035,6 +6062,10 @@ void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt,

if (!Visited.insert(NextTy).second)
continue;
// A dependent type can resolve differently when instantiated, so an
// error-free traversal cannot be reused for later instantiations.
if (NextTy->isDependentType())
CanCacheResult = false;
Comment thread
tahonermann marked this conversation as resolved.

auto EmitHistory = [&]() {
// The first element is always nullptr.
Expand All @@ -6049,6 +6080,7 @@ void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt,
if (NeedToEmitNotes)
EmitHistory();
NeedToEmitNotes = false;
FoundError = true;
}

// In case pointer/array/reference type is met get pointee type, then
Expand All @@ -6063,10 +6095,18 @@ void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt,
if (NeedToEmitNotes)
EmitHistory();
NeedToEmitNotes = false;
FoundError = true;
}
}

if (const auto *RecDecl = NextTy->getAsRecordDecl()) {
// An incomplete record can acquire unsupported fields when completed.
if (!RecDecl->isCompleteDefinition())
CanCacheResult = false;
else if (DeepTypeCheckedRecords.contains(RecDecl))
continue;
else
VisitedRecords.insert(RecDecl);
if (auto *NextFD = dyn_cast<FieldDecl>(Next))
History.push_back(NextFD);
// When nullptr is discovered, this means we've gone back up a level, so
Expand All @@ -6075,6 +6115,9 @@ void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt,
llvm::append_range(StackForRecursion, RecDecl->fields());
}
} while (!StackForRecursion.empty());

if (CanCacheResult && !FoundError)
DeepTypeCheckedRecords.insert_range(VisitedRecords);
}

void SemaSYCL::finalizeSYCLDelayedAnalysis(const FunctionDecl *Caller,
Expand Down Expand Up @@ -8041,7 +8084,7 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) {
for (const VarDecl *VD : GlobalVars) {
VD = VD->getCanonicalDecl();

// Skip if this isn't a SpecIdType, DeviceGlobal, or HostPipe. This
// Skip if this isn't a SpecIdType, DeviceGlobal, or HostPipe. This
// can happen if it was a deduced type.
if (!SemaSYCL::isSyclType(VD->getType(), SYCLTypeAttr::specialization_id) &&
!SemaSYCL::isSyclType(VD->getType(), SYCLTypeAttr::host_pipe) &&
Expand Down
Loading