diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6771,7 +6771,7 @@ def err_objc_object_assignment : Error< "cannot assign to class object (%0 invalid)">; def err_typecheck_invalid_operands : Error< - "invalid operands to binary expression (%0 and %1)">; + "invalid operands to binary expression (%0 and %1)">, Deferrable; def note_typecheck_invalid_operands_converted : Note< "%select{first|second}0 operand was implicitly converted to type %1">; def err_typecheck_logical_vector_expr_gnu_cpp_restrict : Error< diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -1048,9 +1048,6 @@ void destroyCandidates(); - /// Whether diagnostics should be deferred. - bool shouldDeferDiags(Sema &S, ArrayRef Args, SourceLocation OpLoc); - public: OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK, OperatorRewriteInfo RewriteInfo = {}) @@ -1063,6 +1060,9 @@ CandidateSetKind getKind() const { return Kind; } OperatorRewriteInfo getRewriteInfo() const { return RewriteInfo; } + /// Whether diagnostics should be deferred. + bool shouldDeferDiags(Sema &S, ArrayRef Args, SourceLocation OpLoc); + /// Determine when this overload candidate will be new to the /// overload set. bool isNewCandidate(Decl *F, OverloadCandidateParamOrder PO = diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1769,6 +1769,22 @@ /// Build a partial diagnostic. PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h + /// Whether deferrable diagnostics should be deferred. + bool DeferDiags = false; + + /// RAII class to control scope of DeferDiags. + class DeferDiagsRAII { + Sema &S; + bool SavedDeferDiags = false; + + public: + DeferDiagsRAII(Sema &_S, bool DeferDiags) + : S(_S), SavedDeferDiags(S.DeferDiags) { + S.DeferDiags = DeferDiags; + } + ~DeferDiagsRAII() { S.DeferDiags = SavedDeferDiags; } + }; + /// Whether uncompilable error has occurred. This includes error happens /// in deferred diagnostics. bool hasUncompilableErrorOccurred() const; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1790,7 +1790,7 @@ bool IsError = Diags.getDiagnosticIDs()->isDefaultMappingAsError(DiagID); bool ShouldDefer = getLangOpts().CUDA && LangOpts.GPUDeferDiag && DiagnosticIDs::isDeferrable(DiagID) && - (DeferHint || !IsError); + (DeferHint || DeferDiags || !IsError); auto SetIsLastErrorImmediate = [&](bool Flag) { if (IsError) IsLastErrorImmediate = Flag; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -11641,7 +11641,8 @@ CompleteCandidates(S, OCD_AllCandidates, Args, OpLoc, [](auto &Cand) { return (Cand.Viable == false && Cand.FailureKind == ovl_fail_bad_target) || - (Cand.Function->template hasAttr() && + (Cand.Function && + Cand.Function->template hasAttr() && Cand.Function->template hasAttr()); }); DeferHint = !WrongSidedCands.empty(); @@ -13820,6 +13821,8 @@ StringRef OpcStr = BinaryOperator::getOpcodeStr(Opc); auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, Args, OpLoc); + DeferDiagsRAII DDR(*this, + CandidateSet.shouldDeferDiags(*this, Args, OpLoc)); if (Args[0]->getType()->isRecordType() && Opc >= BO_Assign && Opc <= BO_OrAssign) { Diag(OpLoc, diag::err_ovl_no_viable_oper) diff --git a/clang/test/SemaCUDA/deferred-oeverload.cu b/clang/test/SemaCUDA/deferred-oeverload.cu --- a/clang/test/SemaCUDA/deferred-oeverload.cu +++ b/clang/test/SemaCUDA/deferred-oeverload.cu @@ -5,6 +5,11 @@ // RUN: %clang_cc1 -fopenmp -fsyntax-only -verify=host,com %s \ // RUN: -std=c++11 -fgpu-defer-diag +// With -fgpu-defer-diag, clang defers overloading resolution induced +// diagnostics when the full candidates set include host device +// functions or wrong-sided candidates. This roughly matches nvcc's +// behavior. + #include "Inputs/cuda.h" // When callee is called by a host function with integer arguments, there is an error for ambiguity. @@ -31,12 +36,20 @@ __host__ void callee5(float); // com-note {{candidate function}} __host__ void callee5(double); // com-note {{candidate function}} +// When '<<` operator is called by a device function, there is error for 'invalid operands'. +// It should be deferred since it involves wrong-sided candidates. +struct S { + __host__ S &operator <<(int i); // dev-note {{candidate function not viable}} +}; + __host__ void hf() { callee(1); // host-error {{call to 'callee' is ambiguous}} callee2(); callee3(); callee4(); // com-error {{no matching function for call to 'callee4'}} callee5(1); // com-error {{call to 'callee5' is ambiguous}} + S s; + s << 1; undeclared_func(); // com-error {{use of undeclared identifier 'undeclared_func'}} } @@ -45,6 +58,8 @@ callee2(); // dev-error {{no matching function for call to 'callee2'}} callee3(); // dev-error {{no matching function for call to 'callee3'}} callee4(); // com-error {{no matching function for call to 'callee4'}} + S s; + s << 1; // dev-error {{invalid operands to binary expression}} } struct A { int x; typedef int isA; };