diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index be5561dbb71d1..9335037dd01ec 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -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. diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f8d5f7beb603f..a277ea236efd7 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -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(SE)) return SE->getType(); - return cast(SE)->getCallReturnType(Ctx)->getPointeeType(); + else if (auto *CE = dyn_cast(SE)) + return CE->getCallReturnType(Ctx)->getPointeeType(); + return E->getType(); } LValue CodeGenFunction::EmitLValueHelper(const Expr *E, diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index ff216bc6c7535..aa7da0fd1599c 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -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()) @@ -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(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, @@ -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(R.getReflectedDecl()); diff --git a/clang/lib/Sema/SemaReflect.cpp b/clang/lib/Sema/SemaReflect.cpp index 20ef684222c6f..cc9bf5eb1786a 100644 --- a/clang/lib/Sema/SemaReflect.cpp +++ b/clang/lib/Sema/SemaReflect.cpp @@ -70,15 +70,19 @@ Expr *CreateRefToDecl(Sema &S, ValueDecl *D, ExprLoc, &TAListInfo); return ER.get(); } else { + QualType QT(D->getType()); if (isa(D)) ValueKind = VK_PRValue; else if (auto *MD = dyn_cast(D); MD && !MD->isStatic()) ValueKind = VK_PRValue; + else if (auto *RT = dyn_cast(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 @@ -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); @@ -710,9 +714,9 @@ ExprResult Sema::BuildReflectionSpliceExpr( ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back( cast(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: { diff --git a/clang/test/Reflection/info-equality.cpp b/clang/test/Reflection/info-equality.cpp index 3b00f2fb2d023..d98b220dd4ea9 100644 --- a/clang/test/Reflection/info-equality.cpp +++ b/clang/test/Reflection/info-equality.cpp @@ -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; diff --git a/clang/test/Reflection/splice-exprs.cpp b/clang/test/Reflection/splice-exprs.cpp index 1de107cc0ceec..70d2028f92817 100644 --- a/clang/test/Reflection/splice-exprs.cpp +++ b/clang/test/Reflection/splice-exprs.cpp @@ -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 // ============== @@ -72,9 +104,9 @@ template consteval int fn() { return [:R:](); } static_assert(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'; } }; diff --git a/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp b/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp index da49f92729318..a0c35e0c2022e 100644 --- a/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp +++ b/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp @@ -115,6 +115,13 @@ namespace value_of_ref_semantics { return val + value_of(^arg); } static_assert(myfn(5) == 9); + + consteval const int &returnsRef() { return constGlobal; } + + void nonConstFn() { + constexpr auto r = ^returnsRef(); + static_assert(value_of(r) == 2); + } } int main() {