[PATCH] D63960: [C++20] Add consteval-specific semantic for functions
Richard Smith - zygoloid via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 26 14:30:30 PST 2019
rsmith added inline comments.
================
Comment at: clang/include/clang/AST/Expr.h:1033-1035
+ bool IsCausedByImmediateInvocation() const {
+ return ConstantExprBits.IsCausedByImmediateInvocation;
+ }
----------------
I'd remove the "CausedBy" here -- the `ConstantExpr` is our representation of the immediate invocation.
Also, please start this function name with a lowercase `i` for local consistency.
================
Comment at: clang/include/clang/Sema/Sema.h:1027
+ using IICandidate = llvm::PointerIntPair<ConstantExpr *, 1>;
+
----------------
`II` doesn't mean anything to a reader here; please expand the abbreviation.
================
Comment at: clang/include/clang/Sema/Sema.h:5438-5439
+ /// Wrap the expression in a ConstantExpr if it is a potention immediate
+ /// invocation
+ ExprResult CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl);
----------------
potention -> potential
Missing period at end of sentence.
================
Comment at: clang/lib/AST/ExprConstant.cpp:2012-2013
+ if (auto *VD = LVal.getLValueBase().dyn_cast<const ValueDecl *>())
+ if (auto *FD = dyn_cast<FunctionDecl>(VD))
+ if (FD->isConsteval()) {
----------------
Please add braces to these `if` statements (their controlled statement is too long to omit the braces). As a general rule: if an inner construct needs braces, put braces on the outer constructs too.
================
Comment at: clang/lib/AST/ExprConstant.cpp:13618
+ if (InPlace) {
+ LValue LVal;
+ if (!::EvaluateInPlace(Result.Val, Info, LVal, this) ||
----------------
This isn't sufficient: the evaluation process can refer back to the object under construction (eg, via `this`), and we need an lvalue that actually names the result in order for this to work.
I think you'll need to do something like creating a suitable object (perhaps a `LifetimeExtendedTemporaryDecl`) in the caller to represent the result of the immediate invocation, and passing that into here.
================
Comment at: clang/lib/Sema/Sema.cpp:164
isConstantEvaluatedOverride = false;
+ RebuildingImmediateInvocation = false;
----------------
Consider using a default member initializer instead.
================
Comment at: clang/lib/Sema/SemaDecl.cpp:8835-8836
+ // specifier.
+ if (ConstexprKind == CSK_consteval)
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD))
+ if (MD->getOverloadedOperator() == OO_New ||
----------------
Please add braces here.
================
Comment at: clang/lib/Sema/SemaDecl.cpp:8836
+ if (ConstexprKind == CSK_consteval)
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD))
+ if (MD->getOverloadedOperator() == OO_New ||
----------------
This rule also applies to non-member allocator functions. (Don't check for a `CXXMethodDecl` here.)
================
Comment at: clang/lib/Sema/SemaDeclCXX.cpp:11188-11189
+ ConstexprSpecKind ConstexprKind = DetermineSpecialMemberConstexprKind(
+ Constexpr, ClassDecl->hasDefaultedConstevalDefaultCtor());
+
----------------
Tyker wrote:
> rsmith wrote:
> > I don't think this is necessary: implicit special members are never `consteval`. (We use `DeclareImplicitDefaultConstructor` when there is no user-declared default constructor, in which case there can't possibly be a defaulted consteval default constructor.) I don't think you need any of the `DetermineSpecialMemberConstexprKind` machinery, nor the tracking of `DefaultedSpecialMemberIsConsteval` in `CXXRecordDecl`.
> all the code you mention is to fixe an issue i saw while working on consteval.
> the AST of
> ```
> struct A {
> consteval A() = default;
> consteval A(int) { }
> };
> ```
> is
> ```
> TranslationUnitDecl
> `-CXXRecordDecl <line:1:1, line:4:1> line:1:8 struct A definition
> |-DefinitionData pass_in_registers empty standard_layout trivially_copyable trivial literal has_user_declared_ctor has_constexpr_non_copy_move_ctor can_const_default_init
> | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr
> | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
> | |-MoveConstructor exists simple trivial needs_implicit
> | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
> | |-MoveAssignment exists simple trivial needs_implicit
> | `-Destructor simple irrelevant trivial needs_implicit
> |-CXXRecordDecl <col:1, col:8> col:8 implicit referenced struct A
> |-CXXConstructorDecl <line:2:5, col:27> col:15 constexpr A 'void ()' default trivial noexcept-unevaluated 0x55585ae25160
> `-CXXConstructorDecl <line:3:5, col:24> col:15 consteval A 'void (int)'
> |-ParmVarDecl <col:17> col:20 'int'
> `-CompoundStmt <col:22, col:24>
> ```
> [[ https://godbolt.org/z/oRx0Ss | godbolt ]]
> notice that `A::A()` is marked as constexpr instead of consteval.
> and `A::A(int)` is marked correctly.
>
> this is because consteval defaulted special members are not marked as consteval.
> those code changes are intended to fix that. with this patch both constructor are marked as consteval
>
This change is incorrect: an implicit special member is never `consteval`. (Note that implicit special members are the ones the compiler declares for you, not the ones you get from `= default`.) We don't need this, and as a consequence we don't need `DefaultedSpecialMemberIsConsteval` on `DefinitionData`.
================
Comment at: clang/lib/Sema/SemaExpr.cpp:15192
+ FD = cast<FunctionDecl>(Call->getCalleeDecl());
+ else if (auto *Call = dyn_cast<CXXMemberCallExpr>(InnerExpr))
+ FD = Call->getMethodDecl();
----------------
This is unreachable; a `CXXMemberCallExpr` is a `CallExpr` so this was already handled above. Can you just delete this case?
================
Comment at: clang/lib/Sema/SemaExpr.cpp:15197
+ else
+ llvm_unreachable("unhandeld decl kind");
+ assert(FD->isConsteval());
----------------
Typo unhandeld -> unhandled
================
Comment at: clang/lib/Sema/SemaExpr.cpp:15248
+ bool ReplacingOriginal() { return true; }
+ } Transfromer(SemaRef, Rec.ReferenceToConsteval,
+ Rec.ImmediateInvocationCandidates, It);
----------------
Transfromer -> Transformer
================
Comment at: clang/lib/Sema/TreeTransform.h:3451-3452
- if (auto *FE = dyn_cast<FullExpr>(Init))
- Init = FE->getSubExpr();
-
----------------
I'm surprised that we can remove this; I'd expect this to be necessary to properly handle transforming cases such as
```
struct X { X(int); ~X(); int n; };
struct Y { explicit Y(int); };
template<typename T> void f() {
Y y(X(sizeof(sizeof(T))).n);
}
template void f<int>();
```
... where we need to strip off an `ExprWithCleanups` to find the syntactic initializer inside it.
If you want to special-case this from `ComplexRemove`, to make sure you see all `ConstantExpr`s, can you override `TransformInitializer` there instead of changing it globally?
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D63960/new/
https://reviews.llvm.org/D63960
More information about the cfe-commits
mailing list