Skip to content

Commit

Permalink
Fix various bugs related to reflections of lvalues.
Browse files Browse the repository at this point in the history
  • Loading branch information
katzdm committed May 10, 2024
1 parent 9d0f375 commit 7974c91
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 18 deletions.
3 changes: 2 additions & 1 deletion clang/lib/AST/ExprClassification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return Cl::CL_PRValue;
return Cl::CL_LValue;
}
return Cl::CL_PRValue;
return ESE->getOperand()->getValueKind() == VK_LValue ? Cl::CL_LValue :
Cl::CL_PRValue;
}

// Subscripting matrix types behaves like member accesses.
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1509,10 +1509,12 @@ LValue CodeGenFunction::EmitLValue(const Expr *E,

static QualType getConstantExprReferredType(const FullExpr *E,
const ASTContext &Ctx) {
const Expr *SE = E->getSubExpr()->IgnoreImplicit();
const Expr *SE = E->getSubExpr() ? E->getSubExpr()->IgnoreImplicit() : E;
if (isa<OpaqueValueExpr>(SE))
return SE->getType();
return cast<CallExpr>(SE)->getCallReturnType(Ctx)->getPointeeType();
else if (auto *CE = dyn_cast<CallExpr>(SE))
return CE->getCallReturnType(Ctx)->getPointeeType();
return E->getType();
}

LValue CodeGenFunction::EmitLValueHelper(const Expr *E,
Expand Down
23 changes: 19 additions & 4 deletions clang/lib/Sema/Metafunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ static APValue getNthTemplateArgument(Sema &S,
Expr *TExpr = templArgument.getAsExpr();

APValue ArgResult;
bool success = Evaluator(ArgResult, TExpr, true);
bool success = Evaluator(ArgResult, TExpr, !TExpr->isLValue());
assert(success);

if (ArgResult.isReflection())
Expand Down Expand Up @@ -741,8 +741,23 @@ static APValue getNthTemplateArgument(Sema &S,
llvm_unreachable("TemplateArgument::Null not supported");
case TemplateArgument::NullPtr:
llvm_unreachable("TemplateArgument::NullPtr not supported");
case TemplateArgument::StructuralValue:
llvm_unreachable("StructuralValue not implemented");
case TemplateArgument::StructuralValue: {
QualType QT = templArgument.getStructuralValueType();
ExprValueKind VK = VK_PRValue;
if (auto *RT = dyn_cast<ReferenceType>(QT)) {
QT = RT->getPointeeType();
VK = VK_LValue;
}

ConstantExpr *CE =
ConstantExpr::CreateEmpty(S.Context,
ConstantResultStorageKind::APValue);
CE->setType(QT);
CE->setValueKind(VK);
CE->SetResult(templArgument.getAsStructuralValue(), S.Context);

return APValue(ReflectionValue::RK_const_value, CE);
}
case TemplateArgument::Integral: {
ConstantExpr *CE =
ConstantExpr::CreateEmpty(S.Context,
Expand Down Expand Up @@ -1901,7 +1916,7 @@ bool value_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy,
ResultTy.getCanonicalType().getTypePtr())
return true;

return !Evaluator(Result, Synthesized, true);
return !Evaluator(Result, Synthesized, !Synthesized->isLValue());
}
case ReflectionValue::RK_declaration: {
ValueDecl *Decl = dyn_cast<ValueDecl>(R.getReflectedDecl());
Expand Down
16 changes: 10 additions & 6 deletions clang/lib/Sema/SemaReflect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,19 @@ Expr *CreateRefToDecl(Sema &S, ValueDecl *D,
ExprLoc, &TAListInfo);
return ER.get();
} else {
QualType QT(D->getType());
if (isa<EnumConstantDecl>(D))
ValueKind = VK_PRValue;
else if (auto *MD = dyn_cast<CXXMethodDecl>(D); MD && !MD->isStatic())
ValueKind = VK_PRValue;
else if (auto *RT = dyn_cast<ReferenceType>(QT)) {
QT = RT->getPointeeType();
ValueKind = VK_LValue;
}

return DeclRefExpr::Create(
S.Context, NNSLocBuilder.getWithLocInContext(S.Context),
SourceLocation(), D, false, ExprLoc, D->getType(), ValueKind, D,
nullptr);
SourceLocation(), D, false, ExprLoc, QT, ValueKind, D, nullptr);
}
}
} // anonymous namespace
Expand Down Expand Up @@ -389,7 +393,7 @@ ExprResult Sema::BuildCXXReflectExpr(SourceLocation OperatorLoc, Expr *E) {
Expr::EvalResult ER;
ER.Diag = &Diags;

if (!E->EvaluateAsRValue(ER, Context, true)) {
if (!E->EvaluateAsConstantExpr(ER, Context)) {
Diag(E->getExprLoc(), diag::err_reflect_non_constexpr);
for (PartialDiagnosticAt PD : Diags)
Diag(PD.first, PD.second);
Expand Down Expand Up @@ -710,9 +714,9 @@ ExprResult Sema::BuildReflectionSpliceExpr(
ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(
cast<ConstantExpr>(Operand), 0);
}
Operand = CXXExprSpliceExpr::Create(Context, VK_PRValue, TemplateKWLoc,
LSplice, Operand, RSplice, TArgs,
AllowMemberReference);
Operand = CXXExprSpliceExpr::Create(Context, Operand->getValueKind(),
TemplateKWLoc, LSplice, Operand,
RSplice, TArgs, AllowMemberReference);
break;
}
case ReflectionValue::RK_template: {
Expand Down
16 changes: 14 additions & 2 deletions clang/test/Reflection/info-equality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,20 @@ static_assert(i_refl == i_refl_copy);
constexpr int j = 42;
static_assert(^i != ^j);

// CONFIRM: Unspecified?
// static_assert(^42 != ^42);
// Reflections of equal prvalues compare equally.
static_assert(^42 == ^42);

// Reflections of lvalues compare equally iff they designate the same entity.
consteval const int &refOf_i() { return i; }
consteval const int &refOf_j() { return j; }
constexpr auto ref1 = ^refOf_i();
constexpr auto ref2 = ^refOf_i();
constexpr auto ref3 = ^refOf_j();
static_assert(ref1 == ref1);
static_assert(ref1 == ref2);
static_assert(ref1 != ref3);
static_assert(ref1 != ^i);
static_assert(ref1 != ^42);

consteval info local_var_reflection() {
int i;
Expand Down
38 changes: 35 additions & 3 deletions clang/test/Reflection/splice-exprs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,38 @@ consteval int fn() {
static_assert(fn() == 33);
} // namespace with_variables

// =====================
// with_lvalues_and_ptrs
// =====================

namespace with_lvalues_and_ptrs {
struct S { int first, second; };

S s { .first = 10, .second = 12 };
void nonConstFn() {
constexpr auto r1 = ^s.first;
constexpr auto r2 = ^&s.second;

[:r1:] = 11;
*[:r2:] = 22;
}
} // namespace with_lvalues_and_ptrs

// =====================
// with_reference_values
// =====================

namespace with_reference_values {
const int k = 42;

consteval const int &fn() { return k; }

void nonConstFn() {
constexpr auto r = ^fn();
static_assert([:r:] == 42);
}
} // namespace with_reference_values

// ==============
// with_functions
// ==============
Expand All @@ -72,9 +104,9 @@ template <info R> consteval int fn() { return [:R:](); }
static_assert(fn<r_vanilla_fn>() == 42);
} // namespace with_functions

// ============================
// with_shadowed_function_names
// ============================
// ============================
// with_shadowed_function_names
// ============================

namespace with_shadowed_function_names {
struct B { consteval char fn() const { return 'B'; } };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ namespace value_of_ref_semantics {
return val + value_of<int>(^arg);
}
static_assert(myfn(5) == 9);

consteval const int &returnsRef() { return constGlobal; }

void nonConstFn() {
constexpr auto r = ^returnsRef();
static_assert(value_of<const int &>(r) == 2);
}
}

int main() {
Expand Down

0 comments on commit 7974c91

Please sign in to comment.