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