RIscRIpt planned changes to this revision.
RIscRIpt marked 2 inline comments as done.
RIscRIpt added a comment.

> Does it prohibit the inverse?  I think this documentation overall needs a 
> much better description of what the semantics are here, particularly anything 
> that you found in experimentation on the MS implementation.

Do you mean, can `[[msvc::constexpr]]` function call `constexpr` and remain 
const-evaluated? Yes.

From my experiments all Cody's points are valid, except for "An extended 
constexpr function can call other extended constexpr functions without a 
statement-level annotation".

I tried to make doc notes as compact as possible. Recapping his points, which 
were confirmed by tests:

1. `[[msvc::constexpr]]` can be applied only to function definition or a return 
statement.
2. A function can be either `constexpr` or `consteval` or 
`[[msvc::constexpr]]`, but no combination of these.
3. `[[msvc::constexpr]]` function is treated the same way as `constexpr` 
function if it is evaluated in terms of `[[msvc::constexpr]] return` statement, 
otherwise it's a regular function.

By function I mean anything function-like: functions, member-functions, 
constructors, destructors, operators.

In D134475#4287513 <https://reviews.llvm.org/D134475#4287513>, @erichkeane 
wrote:

> Still suspicious about this/whether it models the MSVC implementation 
> correctly, but no real implementation concerns.  I REALLY want us to document 
> the attribute extensively however.

Thanks to your concern I decided to test each point of `[dcl.constexpr]` : 
`9.2.6 The constexpr and consteval specifiers` in Compiler Explorer: 
https://godbolt.org/z/qj3fnK5aW I am going to update tests accordingly.

Regarding on absolute matching MSVC implementation, I am not sure we will be 
able to achieve it with reasonable changes. I am skeptical, because I 
discovered the following test case:

  struct S2 {
      [[msvc::constexpr]] S2() {}
      [[msvc::constexpr]] bool value() { return true; } 
      static constexpr bool check() { [[msvc::constexpr]] return S2{}.value(); }
  };
  static_assert(S2::check());

It's a valid code for MSVC; nothing special https://godbolt.org/z/znnaonEhM
However supporting this code seems to be difficult in Clang:

1. S2 fails checks of "literal type" in this callstack:
  1. [[ 
https://github.com/llvm/llvm-project/blob/bc73ef0/clang/include/clang/AST/DeclCXX.h#L1419-L1445
 | `clang::CXXRecordDecl::isLiteral` ]]
  2. [[ 
https://github.com/llvm/llvm-project/blob/e98776a/clang/lib/AST/Type.cpp#L2746 
| `clang::Type::isLiteralType` ]]
  3. [[ 
https://github.com/llvm/llvm-project/blob/a4edc2c/clang/lib/AST/ExprConstant.cpp#L2317-L2320
 | `CheckLiteralType` ]]
2. We have information about CanEvalMSConstexpr only in `CheckLiteralType`. So, 
currently, I don't see how we can reasonably check whether `S2` is a valid 
literal type in context of `[[msvc::constexpr]]`. Two obvious **ugly** 
solutions are:
  1. Copy all checks from `clang::CXXRecordDecl::isLiteral` to 
`CheckLiteralType` - violates DRY; two places shall be maintained.
  2. Propagate `CanEvalMSConstexpr` down to `clang::CXXRecordDecl::isLiteral`. 
I don't think it's reasonable for supporting rare vendor-specific attribute.



================
Comment at: clang/include/clang/Basic/AttrDocs.td:3543
+definition or a return statement. It has no effect on function declarations.
+This attribute permits constant evaluation of ``[[msvc::constexpr]]`` functions
+in ``[[msvc::constexpr]] return`` statements inside ``constexpr`` or
----------------
erichkeane wrote:
> Does it prohibit the inverse?  I think this documentation overall needs a 
> much better description of what the semantics are here, particularly anything 
> that you found in experimentation on the MS implementation.
> Does it prohibit the inverse?
Do you mean, can `[[msvc::constexpr]]` function call `constexpr` and remain 
const-evaluated? Yes.

I elaborated on semantics in non-inline comment.


================
Comment at: clang/lib/Sema/SemaDeclAttr.cpp:7057-7058
+static void handleMSConstexprAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  if (auto *FD = dyn_cast<FunctionDecl>(D))
+    FD->setConstexprKind(ConstexprSpecKind::Constexpr);
+  D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL));
----------------
RIscRIpt wrote:
> aaron.ballman wrote:
> > We can use `cast` here because we know the declaration must have already 
> > been determined to be a function (from the subjects list in Attr.td).
> > 
> > That said, I think there's more semantic checking we want to do here. For 
> > example, can you use this attribute on a virtual function? What about a 
> > function already marked `constexpr`? Even more scary, what about a function 
> > marked `consteval`?
> > 
> > Also, I presume a `constexpr` function should be able to call an 
> > `[[msvc::constexpr]]` function and vice versa?
> > We can use cast here because we know the declaration must have already been 
> > determined to be a function (from the subjects list in Attr.td).
> 
> Indeed. Changed.
> 
> > That said, I think there's more semantic checking we want to do here. For 
> > example, can you use this attribute on a virtual function? What about a 
> > function already marked constexpr? Even more scary, what about a function 
> > marked consteval?
> 
> Good questions. By running `strings c1xx.dll` I was able to find only the 
> following diagnostic messages regarding `[[msvc::constexpr]]`:
> ```
> [[msvc::constexpr]] may only be applied to statements and functions"
> [[msvc::constexpr]] cannot be applied to a 'constexpr' or 'consteval' 
> function"
> ```
> 
> I've made a similar check here and added relevant test cases in 
> `msvc-attrs-invalid.cpp`. But in order to make it possible, I had to change 
> `FunctionDecl::isConstexpr()`, please check new changes.
> 
> //TODO//: I think, I'll need to read more about `constexpr` for functions in 
> standard (and LLVM code), to add relevant restrictions here.
Added a check that `[[msvc::constexpr]]` function has no `constexpr` or 
`consteval` specifiers. A member function can be `[[msvc::constexpr]]` the same 
way as `constexpr`.

Regarding `virtual` - MSVC does not complain about `[[msvc::constexpr]]`, but 
it fails during constant evaluation (in case of C++17 and earlier).
We have two approaches to address `virtual` case: (1) don't add the attribute 
to the declaration and emit a warning, or (2) check for `virtual` and 
`opts.Cplusplus17` during constant evaluation. I am inclining to (2).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D134475/new/

https://reviews.llvm.org/D134475

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to