Skip to content

Commit 61737eb

Browse files
committed
Compute types of c++ cast expressions
Signed-off-by: Roberto Raggi <[email protected]>
1 parent 08f19f7 commit 61737eb

File tree

4 files changed

+169
-0
lines changed

4 files changed

+169
-0
lines changed

src/parser/cxx/parser.cc

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,9 +2601,109 @@ auto Parser::parse_cpp_cast_expression(ExpressionAST*& yyast,
26012601

26022602
expect(TokenKind::T_RPAREN, ast->rparenLoc);
26032603

2604+
check_cpp_cast_expression(ast);
2605+
2606+
switch (unit->tokenKind(ast->castLoc)) {
2607+
case TokenKind::T_STATIC_CAST:
2608+
if (check_static_cast(ast)) break;
2609+
if (config_.checkTypes) {
2610+
parse_error(ast->firstSourceLocation(), "invalid static_cast");
2611+
}
2612+
break;
2613+
2614+
default:
2615+
break;
2616+
} // switch
2617+
26042618
return true;
26052619
}
26062620

2621+
void Parser::check_cpp_cast_expression(CppCastExpressionAST* ast) {
2622+
if (!ast->typeId) {
2623+
return;
2624+
}
2625+
2626+
ast->type = ast->typeId->type;
2627+
2628+
if (auto refType = type_cast<LvalueReferenceType>(ast->type)) {
2629+
ast->type = refType->elementType();
2630+
ast->valueCategory = ValueCategory::kLValue;
2631+
return;
2632+
}
2633+
2634+
if (auto rvalueRefType = type_cast<RvalueReferenceType>(ast->type)) {
2635+
ast->type = rvalueRefType->elementType();
2636+
2637+
if (type_cast<FunctionType>(ast->type)) {
2638+
ast->valueCategory = ValueCategory::kLValue;
2639+
} else {
2640+
ast->valueCategory = ValueCategory::kXValue;
2641+
}
2642+
}
2643+
}
2644+
2645+
auto Parser::check_static_cast(CppCastExpressionAST* ast) -> bool {
2646+
if (!ast->typeId) return false;
2647+
auto targetType = ast->typeId->type;
2648+
2649+
if (control_->is_void(targetType)) return true;
2650+
2651+
if (check_cast_to_derived(targetType, ast->expression)) return true;
2652+
2653+
const auto cv1 = get_cv_qualifiers(ast->expression->type);
2654+
const auto cv2 = get_cv_qualifiers(targetType);
2655+
if (!check_cv_qualifiers(cv2, cv1)) return false;
2656+
2657+
if (implicit_conversion(ast->expression, ast->type)) return true;
2658+
2659+
return false;
2660+
};
2661+
2662+
auto Parser::check_cv_qualifiers(CvQualifiers target, CvQualifiers source) const
2663+
-> bool {
2664+
if (source == target) return true;
2665+
if (source == CvQualifiers::kNone) return true;
2666+
if (target == CvQualifiers::kConstVolatile) return true;
2667+
return false;
2668+
}
2669+
2670+
auto Parser::check_cast_to_derived(const Type* targetType,
2671+
ExpressionAST* expression) -> bool {
2672+
if (!is_lvalue(expression)) return false;
2673+
2674+
auto sourceType = expression->type;
2675+
2676+
CvQualifiers cv1 = CvQualifiers::kNone;
2677+
if (auto qualType = type_cast<QualType>(sourceType)) {
2678+
cv1 = qualType->cvQualifiers();
2679+
sourceType = qualType->elementType();
2680+
}
2681+
2682+
auto targetRefType = type_cast<LvalueReferenceType>(targetType);
2683+
if (!targetRefType) return false;
2684+
2685+
targetType = targetRefType->elementType();
2686+
2687+
CvQualifiers cv2 = CvQualifiers::kNone;
2688+
if (auto qualType = type_cast<QualType>(targetType)) {
2689+
cv2 = qualType->cvQualifiers();
2690+
targetType = qualType->elementType();
2691+
}
2692+
2693+
if (!check_cv_qualifiers(cv2, cv1)) return false;
2694+
2695+
if (!control_->is_base_of(sourceType, targetType)) return false;
2696+
2697+
return true;
2698+
}
2699+
2700+
auto Parser::get_cv_qualifiers(const Type* type) const -> CvQualifiers {
2701+
if (auto qualType = type_cast<QualType>(type)) {
2702+
return qualType->cvQualifiers();
2703+
}
2704+
return CvQualifiers::kNone;
2705+
}
2706+
26072707
auto Parser::parse_builtin_bit_cast_expression(ExpressionAST*& yyast,
26082708
const ExprContext& ctx) -> bool {
26092709
if (!lookat(TokenKind::T___BUILTIN_BIT_CAST)) return false;

src/parser/cxx/parser.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,18 @@ class Parser final {
872872
[[nodiscard]] auto is_null_pointer_constant(ExpressionAST* expr) const
873873
-> bool;
874874

875+
void check_cpp_cast_expression(CppCastExpressionAST* ast);
876+
877+
[[nodiscard]] auto check_static_cast(CppCastExpressionAST* ast) -> bool;
878+
879+
[[nodiscard]] auto check_cv_qualifiers(CvQualifiers target,
880+
CvQualifiers source) const -> bool;
881+
882+
[[nodiscard]] auto check_cast_to_derived(const Type* targetType,
883+
ExpressionAST* expression) -> bool;
884+
885+
[[nodiscard]] auto get_cv_qualifiers(const Type* type) const -> CvQualifiers;
886+
875887
[[nodiscard]] auto is_prvalue(ExpressionAST* expr) const -> bool;
876888
[[nodiscard]] auto is_lvalue(ExpressionAST* expr) const -> bool;
877889
[[nodiscard]] auto is_xvalue(ExpressionAST* expr) const -> bool;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %cxx -verify -fcheck %s
2+
3+
struct X {};
4+
5+
using F = int();
6+
7+
int f() { return 0; }
8+
9+
auto main() -> int {
10+
X x;
11+
12+
F&& rf = f;
13+
14+
// prvalue
15+
static_assert(__is_reference(decltype(static_cast<X>(x))) == false);
16+
17+
// lvalue if lvalue reference to object type
18+
static_assert(__is_lvalue_reference(decltype(static_cast<X&>(x))));
19+
20+
// rvalue if rvalue reference to object type
21+
static_assert(__is_rvalue_reference(decltype(static_cast<X&&>(x))));
22+
23+
// prvalue
24+
static_assert(__is_reference(decltype(static_cast<F*>(f))) == false);
25+
26+
// lvalue if lvalue reference to function type
27+
static_assert(__is_lvalue_reference(decltype(static_cast<F&>(f))));
28+
29+
// lvalue if rvalue reference to function type
30+
static_assert(__is_lvalue_reference(decltype(static_cast<F&&>(f))));
31+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %cxx -verify -fcheck -freport-missing-types %s
2+
3+
struct B {};
4+
struct D : B {};
5+
6+
auto main() -> int {
7+
B b;
8+
const B cb;
9+
10+
// check casts to void
11+
static_cast<void>(b);
12+
static_cast<const void>(b);
13+
static_cast<volatile void>(b);
14+
static_cast<void>(123);
15+
static_cast<void>(cb);
16+
17+
// check casts to derived class
18+
D& d = static_cast<D&>(b);
19+
const D& cd1 = static_cast<const D&>(b);
20+
const D& cd2 = static_cast<const D&>(cb);
21+
const volatile D& cd3 = static_cast<const volatile D&>(cb);
22+
23+
D& d = static_cast<D&>(cb); // expected-error {{invalid static_cast}}
24+
25+
return 0;
26+
}

0 commit comments

Comments
 (0)