RIscRIpt updated this revision to Diff 464522.
RIscRIpt retitled this revision from "[AST] Add C++11 attribute 
msvc::constexpr" to "Add C++11 attribute msvc::constexpr".
RIscRIpt added a comment.

Add more tests, don't alter constexprKind of `[[msvc::constexpr]]` functions - 
instead change implementation of `isConstexpr`

In D134475#3827712 <https://reviews.llvm.org/D134475#3827712>, @aaron.ballman 
wrote:

> ... we're missing some significant test coverage for it. I had some 
> suggestions for specific things we should be thinking about, but another 
> useful test would be to modify an existing constexpr test to add a RUN line 
> enabling ms extensions, and use a macro to switch between `constexpr` and 
> `[[msvc::constexpr]]` based on those RUN lines. Basically, ensure that 
> `[[msvc::constexpr]]` gives the same behavior (both in terms of evaluation 
> and in terms of semantic checking) as `constexpr`. WDYT?

That's a good idea. Based on my experiments with MSVC, I am more convinced that 
`constexpr` and `[[msvc::constexpr]]` are synonyms (with some extra 
undocumented (yet?) features by MSFT). I added more tests as per your 
suggestion.
Regarding existing tests, I was able to find only 
`clang/test/AST/Interp/functions.cpp` which uses `constexpr` only with 
functions (otherwise `-Dconstexpr=[[msvc::constexpr]]` would break code in case 
there are `constexpr` variables) - I added `RUN` lines there.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134475

Files:
  clang/include/clang/AST/Decl.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/AST/Decl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/Interp/functions.cpp
  clang/test/AST/msvc-attrs-invalid.cpp
  clang/test/AST/msvc-attrs.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test

Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -83,6 +83,7 @@
 // CHECK-NEXT: LoaderUninitialized (SubjectMatchRule_variable_is_global)
 // CHECK-NEXT: Lockable (SubjectMatchRule_record)
 // CHECK-NEXT: MIGServerRoutine (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_block)
+// CHECK-NEXT: MSConstexpr (SubjectMatchRule_function)
 // CHECK-NEXT: MSStruct (SubjectMatchRule_record)
 // CHECK-NEXT: MaybeUndef (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: MicroMips (SubjectMatchRule_function)
Index: clang/test/AST/msvc-attrs.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/msvc-attrs.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fms-extensions -std=c++20 -ast-dump %s | FileCheck %s
+// RUN: not %clang_cc1 -Werror=ignored-attributes -ast-dump %s 2> %t.stderr.txt
+// RUN: FileCheck -check-prefix CHECK-DIAG-NO-MSX %s < %t.stderr.txt
+
+// CHECK: msvc-attrs.cpp:[[@LINE+3]]:21, col:32> col:26 f0 'void ()'
+// CHECK: MSConstexprAttr 0x{{[0-9a-f]+}} <col:3, col:9>
+// CHECK-DIAG-NO-MSX: msvc-attrs.cpp:[[@LINE+1]]:3: error: 'constexpr' attribute ignored
+[[msvc::constexpr]] void f0() {}
+
+struct s0 {
+  // CHECK: CXXConstructorDecl 0x{{[0-9a-f]+}} <line:[[@LINE+2]]:23, col:29> col:23 s0 'void ()' implicit-inline
+  // CHECK: MSConstexprAttr 0x{{[0-9a-f]+}} <col:5, col:11>
+  [[msvc::constexpr]] s0() {}
+
+  // CHECK: CXXDestructorDecl 0x{{[0-9a-f]+}} <line:[[@LINE+2]]:23, col:30> col:23 ~s0 'void () noexcept' implicit-inline
+  // CHECK: MSConstexprAttr 0x{{[0-9a-f]+}} <col:5, col:11>
+  [[msvc::constexpr]] ~s0() {}
+
+  // CHECK: CXXMethodDecl 0x{{[0-9a-f]+}} <line:[[@LINE+2]]:23, col:42> col:36 used f1 'void ()' virtual implicit-inline
+  // CHECK: MSConstexprAttr 0x{{[0-9a-f]+}} <col:5, col:11>
+  [[msvc::constexpr]] virtual void f1() {}
+};
+
+// Check 'constexpr' and '[[msvc::constexpr]]' functions can call each other
+void f2();
+constexpr void f3();
+
+[[msvc::constexpr]] void f2() { f3(); }
+constexpr void f3() { f2(); }
+
+[[msvc::constexpr]] void f4();
+constexpr void f5();
+
+void f4() { f5(); }
+constexpr void f5() { f4(); }
Index: clang/test/AST/msvc-attrs-invalid.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/msvc-attrs-invalid.cpp
@@ -0,0 +1,14 @@
+// RUN: not %clang_cc1 -fms-extensions -std=c++20 -ast-dump %s 2> %t.stderr.txt
+// RUN: FileCheck %s < %t.stderr.txt
+
+void runtime() {}
+
+// CHECK: msvc-attrs-invalid.cpp:[[@LINE+1]]:26: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
+[[msvc::constexpr]] void f0() { runtime(); }
+
+// CHECK: msvc-attrs-invalid.cpp:[[@LINE+1]]:3: error: {{\[\[}}msvc::constexpr{{]]}} cannot be applied to a 'constexpr' or 'consteval' function 'f1'
+[[msvc::constexpr]] constexpr void f1() {}
+
+// CHECK: msvc-attrs-invalid.cpp:[[@LINE+1]]:3: error: {{\[\[}}msvc::constexpr{{]]}} cannot be applied to a 'constexpr' or 'consteval' function 'f2'
+[[msvc::constexpr]] consteval void f2() {}
+
Index: clang/test/AST/Interp/functions.cpp
===================================================================
--- clang/test/AST/Interp/functions.cpp
+++ clang/test/AST/Interp/functions.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
 // RUN: %clang_cc1 -verify=ref %s
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -verify -Dconstexpr=[[msvc::constexpr]] %s
+// RUN: %clang_cc1 -fms-extensions -verify=ref -Dconstexpr=[[msvc::constexpr]] %s
 
 // expected-no-diagnostics
 // ref-no-diagnostics
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -7050,6 +7050,15 @@
   D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL));
 }
 
+static void handleMSConstexprAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  auto *FD = cast<FunctionDecl>(D);
+  if (FD->isConstexprSpecified() || FD->isConsteval()) {
+    S.Diag(AL.getLoc(), diag::err_ms_constexpr_not_distinct) << FD;
+    return;
+  }
+  D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL));
+}
+
 static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   SmallVector<StringRef, 4> Tags;
   for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
@@ -8987,6 +8996,9 @@
   case ParsedAttr::AT_Thread:
     handleDeclspecThreadAttr(S, D, AL);
     break;
+  case ParsedAttr::AT_MSConstexpr:
+    handleMSConstexprAttr(S, D, AL);
+    break;
 
   // HLSL attributes:
   case ParsedAttr::AT_HLSLNumThreads:
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -3121,6 +3121,10 @@
       Parent->markedVirtualFunctionPure();
 }
 
+bool FunctionDecl::isConstexpr() const {
+  return getConstexprKind() != ConstexprSpecKind::Unspecified || hasAttr<MSConstexprAttr>();
+}
+
 template<std::size_t Len>
 static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) {
   IdentifierInfo *II = ND->getIdentifier();
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2777,6 +2777,8 @@
   InGroup<CXXPre14Compat>, DefaultIgnore;
 def note_constexpr_body_previous_return : Note<
   "previous return statement is here">;
+def err_ms_constexpr_not_distinct : Error<
+  "[[msvc::constexpr]] cannot be applied to a 'constexpr' or 'consteval' function %0">;
 
 // C++20 function try blocks in constexpr
 def ext_constexpr_function_try_block_cxx20 : ExtWarn<
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -3478,6 +3478,14 @@
 }];
 }
 
+def MSConstexprDocs : Documentation {
+  let Category = DocCatStmt;
+  let Content = [{
+This attribute is an alias of ``constexpr`` for functions.
+Available only as Microsoft extension (``-fms-extensions``).
+  }];
+}
+
 def MSNoVTableDocs : Documentation {
   let Category = DocCatDecl;
   let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -3500,6 +3500,13 @@
 
 // Microsoft-related attributes
 
+def MSConstexpr : InheritableAttr {
+  let LangOpts = [MicrosoftExt];
+  let Spellings = [CXX11<"msvc", "constexpr">];
+  let Subjects = SubjectList<[Function]>;
+  let Documentation = [MSConstexprDocs];
+}
+
 def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
   let Spellings = [Declspec<"novtable">];
   let Subjects = SubjectList<[CXXRecord]>;
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -2312,9 +2312,7 @@
   }
 
   /// Whether this is a (C++11) constexpr function or constexpr constructor.
-  bool isConstexpr() const {
-    return getConstexprKind() != ConstexprSpecKind::Unspecified;
-  }
+  bool isConstexpr() const;
   void setConstexprKind(ConstexprSpecKind CSK) {
     FunctionDeclBits.ConstexprKind = static_cast<uint64_t>(CSK);
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to