Skip to content

[clang] Introduce SemaPseudoObject #92646

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 21, 2024
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
57 changes: 21 additions & 36 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ class SemaHLSL;
class SemaObjC;
class SemaOpenACC;
class SemaOpenMP;
class SemaPseudoObject;
class SemaSYCL;
class StandardConversionSequence;
class Stmt;
Expand Down Expand Up @@ -470,20 +471,19 @@ class Sema final : public SemaBase {
// 18. Name Lookup (SemaLookup.cpp)
// 19. Modules (SemaModule.cpp)
// 20. C++ Overloading (SemaOverload.cpp)
// 21. Pseudo-Object (SemaPseudoObject.cpp)
// 22. Statements (SemaStmt.cpp)
// 23. `inline asm` Statement (SemaStmtAsm.cpp)
// 24. Statement Attribute Handling (SemaStmtAttr.cpp)
// 25. C++ Templates (SemaTemplate.cpp)
// 26. C++ Template Argument Deduction (SemaTemplateDeduction.cpp)
// 27. C++ Template Instantiation (SemaTemplateInstantiate.cpp)
// 28. C++ Template Declaration Instantiation
// 21. Statements (SemaStmt.cpp)
// 22. `inline asm` Statement (SemaStmtAsm.cpp)
// 23. Statement Attribute Handling (SemaStmtAttr.cpp)
// 24. C++ Templates (SemaTemplate.cpp)
// 25. C++ Template Argument Deduction (SemaTemplateDeduction.cpp)
// 26. C++ Template Instantiation (SemaTemplateInstantiate.cpp)
// 27. C++ Template Declaration Instantiation
// (SemaTemplateInstantiateDecl.cpp)
// 29. C++ Variadic Templates (SemaTemplateVariadic.cpp)
// 30. Constraints and Concepts (SemaConcept.cpp)
// 31. Types (SemaType.cpp)
// 32. FixIt Helpers (SemaFixItUtils.cpp)
// 33. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp)
// 28. C++ Variadic Templates (SemaTemplateVariadic.cpp)
// 29. Constraints and Concepts (SemaConcept.cpp)
// 30. Types (SemaType.cpp)
// 31. FixIt Helpers (SemaFixItUtils.cpp)
// 32. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp)

/// \name Semantic Analysis
/// Implementations are in Sema.cpp
Expand Down Expand Up @@ -1014,6 +1014,11 @@ class Sema final : public SemaBase {
return *OpenMPPtr;
}

SemaPseudoObject &PseudoObject() {
assert(PseudoObjectPtr);
return *PseudoObjectPtr;
}

SemaSYCL &SYCL() {
assert(SYCLPtr);
return *SYCLPtr;
Expand Down Expand Up @@ -1055,6 +1060,7 @@ class Sema final : public SemaBase {
std::unique_ptr<SemaObjC> ObjCPtr;
std::unique_ptr<SemaOpenACC> OpenACCPtr;
std::unique_ptr<SemaOpenMP> OpenMPPtr;
std::unique_ptr<SemaPseudoObject> PseudoObjectPtr;
std::unique_ptr<SemaSYCL> SYCLPtr;

///@}
Expand Down Expand Up @@ -6370,6 +6376,8 @@ class Sema final : public SemaBase {
llvm::SmallVector<std::pair<SourceLocation, const BlockDecl *>, 1>
ImplicitlyRetainedSelfLocs;

void maybeExtendBlockObject(ExprResult &E);

private:
static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind);

Expand Down Expand Up @@ -8368,29 +8376,6 @@ class Sema final : public SemaBase {
//
//

/// \name Pseudo-Object
/// Implementations are in SemaPseudoObject.cpp
///@{

public:
void maybeExtendBlockObject(ExprResult &E);

ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc,
UnaryOperatorKind Opcode, Expr *Op);
ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opcode, Expr *LHS,
Expr *RHS);
ExprResult checkPseudoObjectRValue(Expr *E);
Expr *recreateSyntacticForm(PseudoObjectExpr *E);

///@}

//
//
// -------------------------------------------------------------------------
//
//

/// \name Statements
/// Implementations are in SemaStmt.cpp
///@{
Expand Down
40 changes: 40 additions & 0 deletions clang/include/clang/Sema/SemaPseudoObject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===----- SemaPseudoObject.h --- Semantic Analysis for Pseudo-Objects ----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis for expressions involving
// pseudo-object references.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMAPSEUDOOBJECT_H
#define LLVM_CLANG_SEMA_SEMAPSEUDOOBJECT_H

#include "clang/AST/Expr.h"
#include "clang/AST/OperationKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaBase.h"

namespace clang {

class SemaPseudoObject : public SemaBase {
public:
SemaPseudoObject(Sema &S);

ExprResult checkIncDec(Scope *S, SourceLocation OpLoc,
UnaryOperatorKind Opcode, Expr *Op);
ExprResult checkAssignment(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opcode, Expr *LHS, Expr *RHS);
ExprResult checkRValue(Expr *E);
Expr *recreateSyntacticForm(PseudoObjectExpr *E);
};

} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMAPSEUDOOBJECT_H
2 changes: 2 additions & 0 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenACC.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaPseudoObject.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
Expand Down Expand Up @@ -210,6 +211,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ObjCPtr(std::make_unique<SemaObjC>(*this)),
OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
OpenMPPtr(std::make_unique<SemaOpenMP>(*this)),
PseudoObjectPtr(std::make_unique<SemaPseudoObject>(*this)),
SYCLPtr(std::make_unique<SemaSYCL>(*this)),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaPseudoObject.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
Expand Down Expand Up @@ -15282,7 +15283,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
LHSExpr = LHS.get();
RHSExpr = RHS.get();

// We want to end up calling one of checkPseudoObjectAssignment
// We want to end up calling one of SemaPseudoObject::checkAssignment
// (if the LHS is a pseudo-object), BuildOverloadedBinOp (if
// both expressions are overloadable or either is type-dependent),
// or CreateBuiltinBinOp (in any other case). We also want to get
Expand All @@ -15293,7 +15294,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
// Assignments with a pseudo-object l-value need special analysis.
if (pty->getKind() == BuiltinType::PseudoObject &&
BinaryOperator::isAssignmentOp(Opc))
return checkPseudoObjectAssignment(S, OpLoc, Opc, LHSExpr, RHSExpr);
return PseudoObject().checkAssignment(S, OpLoc, Opc, LHSExpr, RHSExpr);

// Don't resolve overloads if the other type is overloadable.
if (getLangOpts().CPlusPlus && pty->getKind() == BuiltinType::Overload) {
Expand Down Expand Up @@ -15716,7 +15717,7 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
// Increment and decrement of pseudo-object references.
if (pty->getKind() == BuiltinType::PseudoObject &&
UnaryOperator::isIncrementDecrementOp(Opc))
return checkPseudoObjectIncDec(S, OpLoc, Opc, Input);
return PseudoObject().checkIncDec(S, OpLoc, Opc, Input);

// extension is always a builtin operator.
if (Opc == UO_Extension)
Expand Down Expand Up @@ -20933,7 +20934,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {

// Pseudo-objects.
case BuiltinType::PseudoObject:
return checkPseudoObjectRValue(E);
return PseudoObject().checkRValue(E);

case BuiltinType::BuiltinFn: {
// Accept __noop without parens by implicitly converting it to a call expr.
Expand Down
75 changes: 39 additions & 36 deletions clang/lib/Sema/SemaPseudoObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
//
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaPseudoObject.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/CharInfo.h"
Expand Down Expand Up @@ -1446,73 +1447,73 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl,
// General Sema routines.
//===----------------------------------------------------------------------===//

ExprResult Sema::checkPseudoObjectRValue(Expr *E) {
ExprResult SemaPseudoObject::checkRValue(Expr *E) {
Expr *opaqueRef = E->IgnoreParens();
if (ObjCPropertyRefExpr *refExpr
= dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
ObjCPropertyOpBuilder builder(*this, refExpr, true);
ObjCPropertyOpBuilder builder(SemaRef, refExpr, true);
return builder.buildRValueOperation(E);
}
else if (ObjCSubscriptRefExpr *refExpr
= dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) {
ObjCSubscriptOpBuilder builder(*this, refExpr, true);
ObjCSubscriptOpBuilder builder(SemaRef, refExpr, true);
return builder.buildRValueOperation(E);
} else if (MSPropertyRefExpr *refExpr
= dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
MSPropertyOpBuilder builder(*this, refExpr, true);
MSPropertyOpBuilder builder(SemaRef, refExpr, true);
return builder.buildRValueOperation(E);
} else if (MSPropertySubscriptExpr *RefExpr =
dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) {
MSPropertyOpBuilder Builder(*this, RefExpr, true);
MSPropertyOpBuilder Builder(SemaRef, RefExpr, true);
return Builder.buildRValueOperation(E);
} else {
llvm_unreachable("unknown pseudo-object kind!");
}
}

/// Check an increment or decrement of a pseudo-object expression.
ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
ExprResult SemaPseudoObject::checkIncDec(Scope *Sc, SourceLocation opcLoc,
UnaryOperatorKind opcode, Expr *op) {
// Do nothing if the operand is dependent.
if (op->isTypeDependent())
return UnaryOperator::Create(Context, op, opcode, Context.DependentTy,
VK_PRValue, OK_Ordinary, opcLoc, false,
CurFPFeatureOverrides());
return UnaryOperator::Create(
SemaRef.Context, op, opcode, SemaRef.Context.DependentTy, VK_PRValue,
OK_Ordinary, opcLoc, false, SemaRef.CurFPFeatureOverrides());

assert(UnaryOperator::isIncrementDecrementOp(opcode));
Expr *opaqueRef = op->IgnoreParens();
if (ObjCPropertyRefExpr *refExpr
= dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
ObjCPropertyOpBuilder builder(*this, refExpr, false);
ObjCPropertyOpBuilder builder(SemaRef, refExpr, false);
return builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
} else if (isa<ObjCSubscriptRefExpr>(opaqueRef)) {
Diag(opcLoc, diag::err_illegal_container_subscripting_op);
return ExprError();
} else if (MSPropertyRefExpr *refExpr
= dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
MSPropertyOpBuilder builder(*this, refExpr, false);
MSPropertyOpBuilder builder(SemaRef, refExpr, false);
return builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
} else if (MSPropertySubscriptExpr *RefExpr
= dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) {
MSPropertyOpBuilder Builder(*this, RefExpr, false);
MSPropertyOpBuilder Builder(SemaRef, RefExpr, false);
return Builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
} else {
llvm_unreachable("unknown pseudo-object kind!");
}
}

ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
ExprResult SemaPseudoObject::checkAssignment(Scope *S, SourceLocation opcLoc,
BinaryOperatorKind opcode,
Expr *LHS, Expr *RHS) {
// Do nothing if either argument is dependent.
if (LHS->isTypeDependent() || RHS->isTypeDependent())
return BinaryOperator::Create(Context, LHS, RHS, opcode,
Context.DependentTy, VK_PRValue, OK_Ordinary,
opcLoc, CurFPFeatureOverrides());
return BinaryOperator::Create(
SemaRef.Context, LHS, RHS, opcode, SemaRef.Context.DependentTy,
VK_PRValue, OK_Ordinary, opcLoc, SemaRef.CurFPFeatureOverrides());

// Filter out non-overload placeholder types in the RHS.
if (RHS->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(RHS);
ExprResult result = SemaRef.CheckPlaceholderExpr(RHS);
if (result.isInvalid()) return ExprError();
RHS = result.get();
}
Expand All @@ -1521,20 +1522,20 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
Expr *opaqueRef = LHS->IgnoreParens();
if (ObjCPropertyRefExpr *refExpr
= dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
ObjCPropertyOpBuilder builder(*this, refExpr, IsSimpleAssign);
ObjCPropertyOpBuilder builder(SemaRef, refExpr, IsSimpleAssign);
return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
} else if (ObjCSubscriptRefExpr *refExpr
= dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) {
ObjCSubscriptOpBuilder builder(*this, refExpr, IsSimpleAssign);
ObjCSubscriptOpBuilder builder(SemaRef, refExpr, IsSimpleAssign);
return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
} else if (MSPropertyRefExpr *refExpr
= dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
MSPropertyOpBuilder builder(*this, refExpr, IsSimpleAssign);
return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
MSPropertyOpBuilder builder(SemaRef, refExpr, IsSimpleAssign);
return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
} else if (MSPropertySubscriptExpr *RefExpr
= dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) {
MSPropertyOpBuilder Builder(*this, RefExpr, IsSimpleAssign);
return Builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
MSPropertyOpBuilder Builder(SemaRef, RefExpr, IsSimpleAssign);
return Builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
} else {
llvm_unreachable("unknown pseudo-object kind!");
}
Expand All @@ -1557,36 +1558,38 @@ static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) {
/// This is a hack which should be removed when TreeTransform is
/// capable of rebuilding a tree without stripping implicit
/// operations.
Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
Expr *SemaPseudoObject::recreateSyntacticForm(PseudoObjectExpr *E) {
Expr *syntax = E->getSyntacticForm();
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
return UnaryOperator::Create(Context, op, uop->getOpcode(), uop->getType(),
uop->getValueKind(), uop->getObjectKind(),
uop->getOperatorLoc(), uop->canOverflow(),
CurFPFeatureOverrides());
Expr *op = stripOpaqueValuesFromPseudoObjectRef(SemaRef, uop->getSubExpr());
return UnaryOperator::Create(
SemaRef.Context, op, uop->getOpcode(), uop->getType(),
uop->getValueKind(), uop->getObjectKind(), uop->getOperatorLoc(),
uop->canOverflow(), SemaRef.CurFPFeatureOverrides());
} else if (CompoundAssignOperator *cop
= dyn_cast<CompoundAssignOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(SemaRef, cop->getLHS());
Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr();
return CompoundAssignOperator::Create(
Context, lhs, rhs, cop->getOpcode(), cop->getType(),
SemaRef.Context, lhs, rhs, cop->getOpcode(), cop->getType(),
cop->getValueKind(), cop->getObjectKind(), cop->getOperatorLoc(),
CurFPFeatureOverrides(), cop->getComputationLHSType(),
SemaRef.CurFPFeatureOverrides(), cop->getComputationLHSType(),
cop->getComputationResultType());

} else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(SemaRef, bop->getLHS());
Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
return BinaryOperator::Create(Context, lhs, rhs, bop->getOpcode(),
return BinaryOperator::Create(SemaRef.Context, lhs, rhs, bop->getOpcode(),
bop->getType(), bop->getValueKind(),
bop->getObjectKind(), bop->getOperatorLoc(),
CurFPFeatureOverrides());
SemaRef.CurFPFeatureOverrides());

} else if (isa<CallExpr>(syntax)) {
return syntax;
} else {
assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
return stripOpaqueValuesFromPseudoObjectRef(SemaRef, syntax);
}
}

SemaPseudoObject::SemaPseudoObject(Sema &S) : SemaBase(S) {}
Loading
Loading