Skip to content

Commit

Permalink
Require leading 'this->' to access a member through a splice.
Browse files Browse the repository at this point in the history
Closes issue #25.
  • Loading branch information
katzdm committed Apr 3, 2024
1 parent de7203a commit f04ee30
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 23 deletions.
10 changes: 8 additions & 2 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -5592,20 +5592,26 @@ class CXXExprSpliceExpr : public Expr {
SourceLocation LSpliceLoc;
Expr *Operand;
SourceLocation RSpliceLoc;
bool AllowMemberReference;

CXXExprSpliceExpr(QualType ResultTy, ExprValueKind ValueKind,
SourceLocation LSpliceLoc, Expr *Operand,
SourceLocation RSpliceLoc);
SourceLocation RSpliceLoc, bool AllowMemberReference);

public:
static CXXExprSpliceExpr *Create(ASTContext &C, ExprValueKind ValueKind,
SourceLocation LSpliceLoc, Expr *Operand,
SourceLocation RpliceLoc);
SourceLocation RSpliceLoc,
bool AllowMemberReference);

Expr *getOperand() const {
return Operand;
}

bool allowMemberReference() const {
return AllowMemberReference;
}

SourceLocation getLSpliceLoc() const {
return LSpliceLoc;
}
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3109,6 +3109,10 @@ def err_unsupported_splice_kind : Error<
"%select{supported|implemented}2">;
def err_using_dependent_namespace : Error<
"dependent namespaces cannot appear in a using directive">;
def err_dependent_splice_implicit_member_reference : Error<
"cannot implicitly reference a class member through a splice">;
def note_dependent_splice_explicit_this_may_fix : Note<
"an explicit 'this' pointer may fix the problem">;

// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3800,7 +3800,7 @@ class Parser : public CodeCompletionHandler {
bool ParseCXXIndeterminateSplice();

TypeResult ParseCXXSpliceAsType(bool AllowDependent, bool Complain);
ExprResult ParseCXXSpliceAsExpr();
ExprResult ParseCXXSpliceAsExpr(bool AllowMemberReference);
DeclResult ParseCXXSpliceAsNamespace();

//===--------------------------------------------------------------------===//
Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -14865,7 +14865,8 @@ class Sema final {
bool Complain);
ExprResult ActOnCXXSpliceExpectingExpr(SourceLocation LSplice,
Expr *Operand,
SourceLocation RSplice);
SourceLocation RSplice,
bool AllowMemberReference);
DeclResult ActOnCXXSpliceExpectingNamespace(SourceLocation LSplice,
Expr *Operand,
SourceLocation RSplice);
Expand Down Expand Up @@ -14911,9 +14912,9 @@ class Sema final {
SourceLocation LSpliceLoc,
Expr *E, SourceLocation RSpliceLoc,
bool Complain);
ExprResult BuildReflectionSpliceExpr(SourceLocation LSplice,
Expr *Operand,
SourceLocation RSplice);
ExprResult BuildReflectionSpliceExpr(SourceLocation LSplice, Expr *Operand,
SourceLocation RSplice,
bool AllowMemberReference);
DeclResult BuildReflectionSpliceNamespace(SourceLocation LSplice,
Expr *Operand,
SourceLocation RSplice);
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2008,23 +2008,26 @@ CXXIndeterminateSpliceExpr *CXXIndeterminateSpliceExpr::Create(

CXXExprSpliceExpr::CXXExprSpliceExpr(QualType ResultTy, ExprValueKind ValueKind,
SourceLocation LSpliceLoc, Expr *Operand,
SourceLocation RSpliceLoc)
SourceLocation RSpliceLoc,
bool AllowMemberReference)
: Expr(CXXExprSpliceExprClass, ResultTy, ValueKind, OK_Ordinary),
LSpliceLoc(LSpliceLoc), Operand(Operand), RSpliceLoc(RSpliceLoc) {
LSpliceLoc(LSpliceLoc), Operand(Operand), RSpliceLoc(RSpliceLoc),
AllowMemberReference(AllowMemberReference) {
setDependence(computeDependence(this));
}

CXXExprSpliceExpr *CXXExprSpliceExpr::Create(ASTContext &C,
ExprValueKind ValueKind,
SourceLocation LSpliceLoc,
Expr *Operand,
SourceLocation RSpliceLoc) {
SourceLocation RSpliceLoc,
bool AllowMemberReference) {
QualType ResultTy = Operand->getType();
if (Operand->isTypeDependent() || Operand->isValueDependent())
ResultTy = C.DependentTy;

return new (C) CXXExprSpliceExpr(ResultTy, ValueKind, LSpliceLoc, Operand,
RSpliceLoc);
RSpliceLoc, AllowMemberReference);
}

StackLocationExpr::StackLocationExpr(QualType ResultTy, SourceRange Range,
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1652,7 +1652,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
case tok::annot_splice: {
// An 'annot_splice' was parsed by 'TryAnnotateTypeOrScopeToken', but it
// could not be spliced as a type; it must be an expression.
Res = ParseCXXSpliceAsExpr();
Res = ParseCXXSpliceAsExpr(/*AllowMemberReference=*/isAddressOfOperand);
break;
}

Expand Down Expand Up @@ -2327,7 +2327,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
SourceLocation Loc = ConsumeToken();
Name.setIdentifier(Id, Loc);
} else if (Tok.is(tok::annot_splice)) {
ExprResult Res = ParseCXXSpliceAsExpr();
ExprResult Res = ParseCXXSpliceAsExpr(/*AllowMemberReference=*/true);
if (!Res.isInvalid() && !Diags.hasErrorOccurred()) {
LHS = Actions.ActOnMemberAccessExpr(
getCurScope(), LHS.get(), OpLoc, OpKind,
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Parse/ParseReflect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ TypeResult Parser::ParseCXXSpliceAsType(bool AllowDependent,
return Result;
}

ExprResult Parser::ParseCXXSpliceAsExpr() {
ExprResult Parser::ParseCXXSpliceAsExpr(bool AllowMemberReference) {
assert(Tok.is(tok::annot_splice) && "expected annot_splice");

Token Splice = Tok;
Expand All @@ -211,7 +211,8 @@ ExprResult Parser::ParseCXXSpliceAsExpr() {
assert(!ER.isInvalid());

ExprResult Result = Actions.ActOnCXXSpliceExpectingExpr(
Splice.getLocation(), ER.get(), Splice.getAnnotationEndLoc());
Splice.getLocation(), ER.get(), Splice.getAnnotationEndLoc(),
AllowMemberReference);
if (!Result.isInvalid())
ConsumeAnnotationToken();

Expand Down
33 changes: 26 additions & 7 deletions clang/lib/Sema/SemaReflect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,10 @@ TypeResult Sema::ActOnCXXSpliceExpectingType(SourceLocation LSpliceLoc,

ExprResult Sema::ActOnCXXSpliceExpectingExpr(SourceLocation LSpliceLoc,
Expr *Operand,
SourceLocation RSpliceLoc) {
return BuildReflectionSpliceExpr(LSpliceLoc, Operand, RSpliceLoc);
SourceLocation RSpliceLoc,
bool AllowMemberReference) {
return BuildReflectionSpliceExpr(LSpliceLoc, Operand, RSpliceLoc,
AllowMemberReference);
}

DeclResult Sema::ActOnCXXSpliceExpectingNamespace(SourceLocation LSpliceLoc,
Expand Down Expand Up @@ -608,7 +610,8 @@ QualType Sema::BuildReflectionSpliceTypeLoc(TypeLocBuilder &TLB,

ExprResult Sema::BuildReflectionSpliceExpr(SourceLocation LSplice,
Expr *Operand,
SourceLocation RSplice) {
SourceLocation RSplice,
bool AllowMemberReference) {
if (isa<CXXIndeterminateSpliceExpr>(Operand) &&
!Operand->isTypeDependent() && !Operand->isValueDependent()) {
SmallVector<PartialDiagnosticAt, 4> Diags;
Expand All @@ -630,14 +633,30 @@ ExprResult Sema::BuildReflectionSpliceExpr(SourceLocation LSplice,

switch (RV.getKind()) {
case ReflectionValue::RK_declaration: {
Decl *TheDecl = RV.getAsDecl();

// Class members may not be implicitly referenced through a splice.
if (!AllowMemberReference &&
(isa<FieldDecl>(TheDecl) ||
(isa<CXXMethodDecl>(TheDecl) &&
dyn_cast<CXXMethodDecl>(TheDecl)->isInstance()))) {
Diag(Operand->getExprLoc(),
diag::err_dependent_splice_implicit_member_reference)
<< Operand->getSourceRange();
Diag(Operand->getExprLoc(),
diag::note_dependent_splice_explicit_this_may_fix);
return ExprError();
}

// Create a new DeclRefExpr, since the operand of the reflect expression
// was parsed in an unevaluated context (but a splice expression is not
// necessarily, and frequently not, in such a context).
Operand = CreateRefToDecl(*this, cast<ValueDecl>(RV.getAsDecl()),
Operand = CreateRefToDecl(*this, cast<ValueDecl>(TheDecl),
Operand->getExprLoc());
MarkDeclRefReferenced(cast<DeclRefExpr>(Operand), nullptr);
Operand = CXXExprSpliceExpr::Create(Context, Operand->getValueKind(),
LSplice, Operand, RSplice);
LSplice, Operand, RSplice,
AllowMemberReference);
break;
}
case ReflectionValue::RK_const_value: {
Expand All @@ -650,7 +669,7 @@ ExprResult Sema::BuildReflectionSpliceExpr(SourceLocation LSplice,
cast<ConstantExpr>(Operand), 0);
}
Operand = CXXExprSpliceExpr::Create(Context, VK_PRValue, LSplice, Operand,
RSplice);
RSplice, AllowMemberReference);
break;
}
case ReflectionValue::RK_template: {
Expand All @@ -670,7 +689,7 @@ ExprResult Sema::BuildReflectionSpliceExpr(SourceLocation LSplice,
return Operand;
}
return CXXExprSpliceExpr::Create(Context, Operand->getValueKind(), LSplice,
Operand, RSplice);
Operand, RSplice, AllowMemberReference);
}

DeclResult Sema::BuildReflectionSpliceNamespace(SourceLocation LSplice,
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -8724,7 +8724,8 @@ TreeTransform<Derived>::TransformCXXExprSpliceExpr(CXXExprSpliceExpr *E) {
return ExprError();

return getSema().BuildReflectionSpliceExpr(E->getLSpliceLoc(), ER.get(),
E->getRSpliceLoc());
E->getRSpliceLoc(),
E->allowMemberReference());
}

template <typename Derived>
Expand Down

0 comments on commit f04ee30

Please sign in to comment.