Skip to content

Commit 3bb0d3e

Browse files
authored
When looking up C++ operators, make sure all operands are complete (#6132)
This diagnoses instead of crashing in some cases: * When one of the operands is an incomplete Carbon type. * When one of the operands is a C++ class that can't be completed due to lack of Carbon supported. The new tests cover these cases. Part of #5995.
1 parent fd70196 commit 3bb0d3e

File tree

4 files changed

+98
-9
lines changed

4 files changed

+98
-9
lines changed

toolchain/check/cpp/operators.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "toolchain/check/cpp/type_mapping.h"
1111
#include "toolchain/check/inst.h"
1212
#include "toolchain/check/type.h"
13+
#include "toolchain/check/type_completion.h"
1314
#include "toolchain/sem_ir/ids.h"
1415

1516
namespace Carbon::Check {
@@ -169,19 +170,33 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
169170
return SemIR::InstId::None;
170171
}
171172

173+
// Make sure all operands are complete before lookup.
174+
for (SemIR::InstId arg_id : arg_ids) {
175+
SemIR::TypeId arg_type_id = context.insts().Get(arg_id).type_id();
176+
if (!RequireCompleteType(context, arg_type_id, loc_id, [&] {
177+
CARBON_DIAGNOSTIC(
178+
IncompleteOperandTypeInCppOperatorLookup, Error,
179+
"looking up a C++ operator with incomplete operand type {0}",
180+
SemIR::TypeId);
181+
return context.emitter().Build(
182+
loc_id, IncompleteOperandTypeInCppOperatorLookup, arg_type_id);
183+
})) {
184+
return SemIR::ErrorInst::InstId;
185+
}
186+
}
187+
172188
auto arg_exprs = InventClangArgs(context, arg_ids);
173189
if (!arg_exprs.has_value()) {
174190
return SemIR::ErrorInst::InstId;
175191
}
176192

177-
clang::Sema& sema = context.clang_sema();
178-
179193
clang::UnresolvedSet<4> functions;
180194
// TODO: Add location accordingly.
181195
clang::OverloadCandidateSet candidate_set(
182196
clang::SourceLocation(), clang::OverloadCandidateSet::CSK_Operator);
183197
// This works for both unary and binary operators.
184-
sema.LookupOverloadedBinOp(candidate_set, *op_kind, functions, *arg_exprs);
198+
context.clang_sema().LookupOverloadedBinOp(candidate_set, *op_kind, functions,
199+
*arg_exprs);
185200

186201
for (auto& it : candidate_set) {
187202
if (!it.Function) {

toolchain/check/operator.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ static auto IsCppClassType(Context& context, SemIR::InstId inst_id) -> bool {
4848
return false;
4949
}
5050

51-
const SemIR::Class& class_info = context.classes().Get(class_type->class_id);
52-
return class_info.is_complete() &&
53-
context.name_scopes().Get(class_info.scope_id).is_cpp_scope();
51+
SemIR::NameScopeId class_scope_id =
52+
context.classes().Get(class_type->class_id).scope_id;
53+
return class_scope_id.has_value() &&
54+
context.name_scopes().Get(class_scope_id).is_cpp_scope();
5455
}
5556

5657
auto BuildUnaryOperator(Context& context, SemIR::LocId loc_id, Operator op,
@@ -64,7 +65,10 @@ auto BuildUnaryOperator(Context& context, SemIR::LocId loc_id, Operator op,
6465
if (IsCppClassType(context, operand_id)) {
6566
SemIR::InstId cpp_inst_id =
6667
LookupCppOperator(context, loc_id, op, {operand_id});
67-
if (cpp_inst_id.has_value() && cpp_inst_id != SemIR::ErrorInst::InstId) {
68+
if (cpp_inst_id.has_value()) {
69+
if (cpp_inst_id == SemIR::ErrorInst::InstId) {
70+
return SemIR::ErrorInst::InstId;
71+
}
6872
return PerformCall(context, loc_id, cpp_inst_id, {operand_id});
6973
}
7074
}
@@ -98,7 +102,10 @@ auto BuildBinaryOperator(Context& context, SemIR::LocId loc_id, Operator op,
98102
if (IsCppClassType(context, lhs_id) || IsCppClassType(context, rhs_id)) {
99103
SemIR::InstId cpp_inst_id =
100104
LookupCppOperator(context, loc_id, op, {lhs_id, rhs_id});
101-
if (cpp_inst_id.has_value() && cpp_inst_id != SemIR::ErrorInst::InstId) {
105+
if (cpp_inst_id.has_value()) {
106+
if (cpp_inst_id == SemIR::ErrorInst::InstId) {
107+
return SemIR::ErrorInst::InstId;
108+
}
102109
return PerformCall(context, loc_id, cpp_inst_id, {lhs_id, rhs_id});
103110
}
104111
}

toolchain/check/testdata/interop/cpp/function/operators.carbon

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ fn F() {
753753
}
754754

755755
// ============================================================================
756-
// Incomplete operand
756+
// Incomplete operand C++ type
757757
// ============================================================================
758758

759759
// --- incomplete.h
@@ -784,6 +784,72 @@ fn F() {
784784
let c3: Cpp.Complete = Cpp.foo(c1 + ({} as Cpp.Incomplete));
785785
}
786786

787+
// ============================================================================
788+
// Incomplete operand Carbon type
789+
// ============================================================================
790+
791+
// --- complete.h
792+
793+
struct Complete {};
794+
795+
// --- fail_incomplete_operand_carbon_type.carbon
796+
797+
library "[[@TEST_NAME]]";
798+
799+
import Cpp library "complete.h";
800+
801+
class Incomplete;
802+
fn CreateIncomplete() -> Incomplete*;
803+
804+
fn F() {
805+
var complete: Cpp.Complete = Cpp.Complete.Complete();
806+
// CHECK:STDERR: fail_incomplete_operand_carbon_type.carbon:[[@LINE+10]]:21: error: looking up a C++ operator with incomplete operand type `Incomplete` [IncompleteOperandTypeInCppOperatorLookup]
807+
// CHECK:STDERR: let result: i32 = *CreateIncomplete() + complete;
808+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
809+
// CHECK:STDERR: fail_incomplete_operand_carbon_type.carbon:[[@LINE-8]]:1: note: class was forward declared here [ClassForwardDeclaredHere]
810+
// CHECK:STDERR: class Incomplete;
811+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
812+
// CHECK:STDERR: fail_incomplete_operand_carbon_type.carbon:[[@LINE+4]]:21: note: in `Cpp` operator `AddWith` lookup [InCppOperatorLookup]
813+
// CHECK:STDERR: let result: i32 = *CreateIncomplete() + complete;
814+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
815+
// CHECK:STDERR:
816+
let result: i32 = *CreateIncomplete() + complete;
817+
}
818+
819+
// ============================================================================
820+
// Unsupported operand type in instantiation
821+
// ============================================================================
822+
823+
// --- unsupported_in_instantiation.h
824+
825+
struct Supported {};
826+
827+
template<typename T>
828+
struct Unsupported : public virtual Supported {};
829+
using UnsupportedAlias = Unsupported<int>;
830+
extern UnsupportedAlias unsupported;
831+
832+
// --- fail_import_unsupported_in_instantiation.carbon
833+
834+
library "[[@TEST_NAME]]";
835+
836+
import Cpp library "unsupported_in_instantiation.h";
837+
838+
fn F() {
839+
var supported: Cpp.Supported = Cpp.Supported.Supported();
840+
// CHECK:STDERR: fail_import_unsupported_in_instantiation.carbon:[[@LINE+10]]:21: error: semantics TODO: `class with virtual bases` [SemanticsTodo]
841+
// CHECK:STDERR: let result: i32 = supported + Cpp.unsupported;
842+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
843+
// CHECK:STDERR: fail_import_unsupported_in_instantiation.carbon:[[@LINE+7]]:21: note: while completing C++ type `Cpp.Unsupported` [InCppTypeCompletion]
844+
// CHECK:STDERR: let result: i32 = supported + Cpp.unsupported;
845+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
846+
// CHECK:STDERR: fail_import_unsupported_in_instantiation.carbon:[[@LINE+4]]:21: note: in `Cpp` operator `AddWith` lookup [InCppOperatorLookup]
847+
// CHECK:STDERR: let result: i32 = supported + Cpp.unsupported;
848+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
849+
// CHECK:STDERR:
850+
let result: i32 = supported + Cpp.unsupported;
851+
}
852+
787853
// ============================================================================
788854
// Operator overloading
789855
// ============================================================================

toolchain/diagnostics/diagnostic_kind.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ CARBON_DIAGNOSTIC_KIND(QualifiedDeclInUndefinedInterfaceScope)
369369
CARBON_DIAGNOSTIC_KIND(InCppNameLookup)
370370
CARBON_DIAGNOSTIC_KIND(InCppOperatorLookup)
371371
CARBON_DIAGNOSTIC_KIND(InNameLookup)
372+
CARBON_DIAGNOSTIC_KIND(IncompleteOperandTypeInCppOperatorLookup)
372373
CARBON_DIAGNOSTIC_KIND(NameAmbiguousDueToExtend)
373374
CARBON_DIAGNOSTIC_KIND(NameNotFound)
374375
CARBON_DIAGNOSTIC_KIND(MemberNameNotFound)

0 commit comments

Comments
 (0)