[PATCH] D84846: [MC] Add support for generating missing GNU build notes

2020-07-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
Herald added subscribers: llvm-commits, cfe-commits, dang, hiraditya, emaste.
Herald added a reviewer: espindola.
Herald added projects: clang, LLVM.
tbaeder requested review of this revision.
Herald added a subscriber: MaskRay.

Add support for generating missing GNU build notes to the LLVM assembler.

This makes clang accept and pass through 
-Wa,--generate-missing-build-notes=[yes/no]. If =yes is passed (the default is 
no), then the assembler will check whether a .gnu.build.attributes section is 
present. If not, it will generate one for all relevant code sections.

This is the equivalent to what the GNU assembler gas is already doing in 
maybe_generate_build_notes() in gas/write.c: 
https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gas/write.c;h=0b43063bbaab76d21fe3bac5fb4643bfff3c72e2;hb=HEAD#l1954


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D84846

Files:
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/tools/driver/cc1as_main.cpp
  llvm/include/llvm/MC/MCContext.h
  llvm/include/llvm/MC/MCTargetOptions.h
  llvm/lib/CodeGen/LLVMTargetMachine.cpp
  llvm/lib/MC/ELFObjectWriter.cpp
  llvm/lib/MC/MCContext.cpp
  llvm/lib/MC/MCTargetOptions.cpp
  llvm/test/MC/ELF/build-notes.s
  llvm/tools/llvm-mc/llvm-mc.cpp

Index: llvm/tools/llvm-mc/llvm-mc.cpp
===
--- llvm/tools/llvm-mc/llvm-mc.cpp
+++ llvm/tools/llvm-mc/llvm-mc.cpp
@@ -172,6 +172,10 @@
 static cl::opt NoExecStack("no-exec-stack",
  cl::desc("File doesn't need an exec stack"));
 
+static cl::opt
+GenerateMissingBuildNotes("generate-missing-build-notes",
+  cl::desc("Generate missing GNU build notes"));
+
 enum ActionType {
   AC_AsLex,
   AC_Assemble,
@@ -378,6 +382,9 @@
   if (SaveTempLabels)
 Ctx.setAllowTemporaryLabels(false);
 
+  if (GenerateMissingBuildNotes)
+Ctx.setGenerateMissingBuildNotes(true);
+
   Ctx.setGenDwarfForAssembly(GenDwarfForAssembly);
   // Default to 4 for dwarf version.
   unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4;
Index: llvm/test/MC/ELF/build-notes.s
===
--- /dev/null
+++ llvm/test/MC/ELF/build-notes.s
@@ -0,0 +1,55 @@
+// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s
+// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple i386-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s --check-prefix=i386
+// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple armeb-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s --check-prefix=armbe32
+
+.text
+.dc.l 1
+
+.section .text.unused,"ax"
+.space 1025
+
+.section .gnu.linkonce,"ax"
+.dc.l 3
+
+// CHECK:  Relocations [
+// CHECK-NEXT:   Section {{.*}} .rela.gnu.build.attributes {
+// CHECK-NEXT: 0x14 R_X86_64_64 .text 0x0
+// CHECK-NEXT: 0x1C R_X86_64_64 .text 0x4
+// CHECK-NEXT: 0x38 R_X86_64_64 .text.unused 0x0
+// CHECK-NEXT: 0x40 R_X86_64_64 .text.unused 0x401
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK: Hex dump of section '.gnu.build.attributes':
+// CHECK-NEXT: 0x 0800 1000 0001 47412401 GA$.
+// CHECK-NEXT: 0x0010 33613200    3a2.
+// CHECK-NEXT: 0x0020  0800 1000 0001 
+// CHECK-NEXT: 0x0030 47412401 33613200   GA$.3a2.
+// CHECK-NEXT: 0x0040     
+
+// i386:  Relocations [
+// i386-NEXT:   Section {{.*}} .rel.gnu.build.attributes {
+// i386-NEXT: 0x14 R_386_32 .text 0x0
+// i386-NEXT: 0x18 R_386_32 .text 0x0
+// i386-NEXT: 0x30 R_386_32 .text.unused 0x0
+// i386-NEXT: 0x34 R_386_32 .text.unused 0x0
+// i386-NEXT:   }
+// i386-NEXT: ]
+// i386: Hex dump of section '.gnu.build.attributes':
+// i386-NEXT: 0x 0800 0800 0001 47412401 GA$.
+// i386-NEXT: 0x0010 33613200  0400 0800 3a2.
+// i386-NEXT: 0x0020 0800 0001 47412401 33613200 GA$.3a2.
+// i386-NEXT: 0x0030  0104   
+
+// armbe32:  Relocations [
+// armbe32-NEXT:   Section {{.*}} .rel.gnu.build.attributes {
+// armbe32-NEXT: 0x14 R_ARM_ABS32 .text 0x0
+// armbe32-NEXT: 0x18 R_ARM_ABS32 .text 0x0
+// armbe32-NEXT: 0x30 R_ARM_ABS32 .text.unused 0x0
+// armbe32-NEXT: 0x34 R_ARM_ABS32

[PATCH] D75844: [clang] Set begin loc on GNU attribute parsed attrs

2020-06-05 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

I'm looking at this again and I am not sure how it is meant to work. For 
example in `Parser::parseClassSpecifier` in `ParseDeclCXX.cpp`.
Here `attrs` is a local variable of type `ParsedAttributesWithRange`, already 
before my patch. `attrs` is then passed to

1. `MaybeParseGNUAttributes`
2. `MaybeParseMicrosoftDeclSpecs`
3. `ParseMicrosoftInheritanceClassAttributes`
4. `MaybeParseCXX11Attributes`

and later `parseClassSpecifier` calls `ProhibitAttributes(attrs)` a few times. 
`ProhibitAttributes` in turn will not do anything if the given attrs have an 
invalid (i.e. unset) range.
So, how could they ever have a valid range set? All the four functions above 
only take a  `ParsedAttributes`, no range.

This is one of the cases that now (that `MaybeParseGNUAttributes` sets the 
range of the given `attrs` if it really parses attributes) generates errors in 
various test cases.
For example in `clang/test/AST/ast-print-record-decl.c`: File 
/home/tbaeder/llvm-project/clang/test/AST/ast-print-record-decl.c Line 209: an 
attribute list cannot appear here

Am I missing something?


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

https://reviews.llvm.org/D75844



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


[PATCH] D84846: [MC] Add support for generating missing GNU build notes

2020-08-10 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 284308.
tbaeder added a comment.

Add a test that checks that clang accepts 
`-Wa,--generate-missing-build-notes=yes` and 
`-Wa,--generate-missing-build-notes=no`


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

https://reviews.llvm.org/D84846

Files:
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/test/Misc/generate-missing-build-notes.c
  clang/tools/driver/cc1as_main.cpp
  llvm/include/llvm/MC/MCContext.h
  llvm/include/llvm/MC/MCTargetOptions.h
  llvm/lib/CodeGen/LLVMTargetMachine.cpp
  llvm/lib/MC/ELFObjectWriter.cpp
  llvm/lib/MC/MCContext.cpp
  llvm/lib/MC/MCTargetOptions.cpp
  llvm/test/MC/ELF/build-notes.s
  llvm/tools/llvm-mc/llvm-mc.cpp

Index: llvm/tools/llvm-mc/llvm-mc.cpp
===
--- llvm/tools/llvm-mc/llvm-mc.cpp
+++ llvm/tools/llvm-mc/llvm-mc.cpp
@@ -172,6 +172,10 @@
 static cl::opt NoExecStack("no-exec-stack",
  cl::desc("File doesn't need an exec stack"));
 
+static cl::opt
+GenerateMissingBuildNotes("generate-missing-build-notes",
+  cl::desc("Generate missing GNU build notes"));
+
 enum ActionType {
   AC_AsLex,
   AC_Assemble,
@@ -378,6 +382,9 @@
   if (SaveTempLabels)
 Ctx.setAllowTemporaryLabels(false);
 
+  if (GenerateMissingBuildNotes)
+Ctx.setGenerateMissingBuildNotes(true);
+
   Ctx.setGenDwarfForAssembly(GenDwarfForAssembly);
   // Default to 4 for dwarf version.
   unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4;
Index: llvm/test/MC/ELF/build-notes.s
===
--- /dev/null
+++ llvm/test/MC/ELF/build-notes.s
@@ -0,0 +1,55 @@
+// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s
+// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple i386-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s --check-prefix=i386
+// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple armeb-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s --check-prefix=armbe32
+
+.text
+.dc.l 1
+
+.section .text.unused,"ax"
+.space 1025
+
+.section .gnu.linkonce,"ax"
+.dc.l 3
+
+// CHECK:  Relocations [
+// CHECK-NEXT:   Section {{.*}} .rela.gnu.build.attributes {
+// CHECK-NEXT: 0x14 R_X86_64_64 .text 0x0
+// CHECK-NEXT: 0x1C R_X86_64_64 .text 0x4
+// CHECK-NEXT: 0x38 R_X86_64_64 .text.unused 0x0
+// CHECK-NEXT: 0x40 R_X86_64_64 .text.unused 0x401
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK: Hex dump of section '.gnu.build.attributes':
+// CHECK-NEXT: 0x 0800 1000 0001 47412401 GA$.
+// CHECK-NEXT: 0x0010 33613200    3a2.
+// CHECK-NEXT: 0x0020  0800 1000 0001 
+// CHECK-NEXT: 0x0030 47412401 33613200   GA$.3a2.
+// CHECK-NEXT: 0x0040     
+
+// i386:  Relocations [
+// i386-NEXT:   Section {{.*}} .rel.gnu.build.attributes {
+// i386-NEXT: 0x14 R_386_32 .text 0x0
+// i386-NEXT: 0x18 R_386_32 .text 0x0
+// i386-NEXT: 0x30 R_386_32 .text.unused 0x0
+// i386-NEXT: 0x34 R_386_32 .text.unused 0x0
+// i386-NEXT:   }
+// i386-NEXT: ]
+// i386: Hex dump of section '.gnu.build.attributes':
+// i386-NEXT: 0x 0800 0800 0001 47412401 GA$.
+// i386-NEXT: 0x0010 33613200  0400 0800 3a2.
+// i386-NEXT: 0x0020 0800 0001 47412401 33613200 GA$.3a2.
+// i386-NEXT: 0x0030  0104   
+
+// armbe32:  Relocations [
+// armbe32-NEXT:   Section {{.*}} .rel.gnu.build.attributes {
+// armbe32-NEXT: 0x14 R_ARM_ABS32 .text 0x0
+// armbe32-NEXT: 0x18 R_ARM_ABS32 .text 0x0
+// armbe32-NEXT: 0x30 R_ARM_ABS32 .text.unused 0x0
+// armbe32-NEXT: 0x34 R_ARM_ABS32 .text.unused 0x0
+// armbe32-NEXT:   }
+// armbe32-NEXT: ]
+// armbe32: Hex dump of section '.gnu.build.attributes':
+// armbe32-NEXT: 0x 0008 0008 0100 47412401 GA$.
+// armbe32-NEXT: 0x0010 33613200  0004 0008 3a2.
+// armbe32-NEXT: 0x0020 0008 0100 47412401 33613200 GA$.3a2.
+// armbe32-NEXT: 0x0030  0401   
Index: llvm/lib/MC/MCTargetOptions.cpp
===
--- llvm/lib/MC/MCTargetOptions

[PATCH] D132749: Expose QualType::getUnqualifiedType in libclang

2022-08-27 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/include/clang-c/Index.h:3775
+ *
+ * Executing \c clang_getUnuqalifiedType() on a \c CXType that
+ * represents \c DifferenceType, will desugar to a type representing

Typo: Unuqualified



Comment at: clang/include/clang-c/Index.h:3779
+ *
+ * And, executing \c clang_getUnuqalifiedType() on the type of the
+ * first argument of the following function declaration:

Same



Comment at: clang/include/clang-c/Index.h:3792
+ * A type can be checked for qualifiers with \c
+ * clang_isConstQualifiedType(), \c clang_isVolativeQualifiedType()
+ * and \c clang_isRestrictQualifiedType().

Typo: Volative


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132749

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


[PATCH] D132821: [clang][Parse] Fix crash when emitting template diagnostic

2022-08-28 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added a reviewer: aaron.ballman.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The integer value of the enum here is `6`, which wasn't covered by the 
diagnostic.

This fixes https://github.com/llvm/llvm-project/issues/57415


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132821

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/test/Parser/cxx-concept-declaration.cpp


Index: clang/test/Parser/cxx-concept-declaration.cpp
===
--- clang/test/Parser/cxx-concept-declaration.cpp
+++ clang/test/Parser/cxx-concept-declaration.cpp
@@ -1,7 +1,14 @@
 
 // Support parsing of concepts
 // Disabled for now.
-// expected-no-diagnostics
 
-// RUN:  %clang_cc1 -std=c++14 -x c++ -verify %s
-// template concept C1 = true;
+// RUN:  %clang_cc1 -std=c++20 -x c++ -verify %s
+template concept C1 = true;
+
+
+
+template
+concept C = true;
+
+template
+class C {}; //expected-error{{identifier followed by '<' indicates a 
class template specialization but 'C' refers to a concept template}}
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -775,7 +775,8 @@
 def err_template_spec_syntax_non_template : Error<
   "identifier followed by '<' indicates a class template specialization but "
   "%0 %select{does not refer to a template|refers to a function template|"
-  "|refers to a variable template||refers to a concept}1">;
+  "|refers to a variable template||refers to a concept|"
+  "refers to a concept template}1">;
 def err_id_after_template_in_nested_name_spec : Error<
   "expected template name after 'template' keyword in nested name specifier">;
 def err_unexpected_template_in_unqualified_id : Error<


Index: clang/test/Parser/cxx-concept-declaration.cpp
===
--- clang/test/Parser/cxx-concept-declaration.cpp
+++ clang/test/Parser/cxx-concept-declaration.cpp
@@ -1,7 +1,14 @@
 
 // Support parsing of concepts
 // Disabled for now.
-// expected-no-diagnostics
 
-// RUN:  %clang_cc1 -std=c++14 -x c++ -verify %s
-// template concept C1 = true;
+// RUN:  %clang_cc1 -std=c++20 -x c++ -verify %s
+template concept C1 = true;
+
+
+
+template
+concept C = true;
+
+template
+class C {}; //expected-error{{identifier followed by '<' indicates a class template specialization but 'C' refers to a concept template}}
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -775,7 +775,8 @@
 def err_template_spec_syntax_non_template : Error<
   "identifier followed by '<' indicates a class template specialization but "
   "%0 %select{does not refer to a template|refers to a function template|"
-  "|refers to a variable template||refers to a concept}1">;
+  "|refers to a variable template||refers to a concept|"
+  "refers to a concept template}1">;
 def err_id_after_template_in_nested_name_spec : Error<
   "expected template name after 'template' keyword in nested name specifier">;
 def err_unexpected_template_in_unqualified_id : Error<
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132829: [clang][Interp] Handle ImplictValueInitExprs

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, shafik, erichkeane, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

I don't have a test case handy for them since I'm not sure how to trigger them 
reliably, but they are easy enough to implement and I ran into them while 
working on array fillers.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132829

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Opcodes.td


Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -203,6 +203,7 @@
 // [] -> [Integer]
 def Zero : Opcode {
   let Types = [AluTypeClass];
+  let HasGroup = 1;
 }
 
 // [] -> [Pointer]
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -67,6 +67,7 @@
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
   bool VisitInitListExpr(const InitListExpr *E);
+  bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -259,6 +259,14 @@
   return true;
 }
 
+template 
+bool ByteCodeExprGen::VisitImplicitValueInitExpr(const 
ImplicitValueInitExpr *E) {
+  if (Optional T = classify(E))
+return this->emitZero(*T, E);
+
+  return false;
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);


Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -203,6 +203,7 @@
 // [] -> [Integer]
 def Zero : Opcode {
   let Types = [AluTypeClass];
+  let HasGroup = 1;
 }
 
 // [] -> [Pointer]
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -67,6 +67,7 @@
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
   bool VisitInitListExpr(const InitListExpr *E);
+  bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -259,6 +259,14 @@
   return true;
 }
 
+template 
+bool ByteCodeExprGen::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+  if (Optional T = classify(E))
+return this->emitZero(*T, E);
+
+  return false;
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132831: [clang][Interp] Handle SubstNonTypeTemplateParmExprs

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, shafik, erichkeane, tahonermann.
Herald added a subscriber: kristof.beyls.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

These are also easy to add and used in a unit test that I'd like to get working 
with the new interpreter.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132831

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/test/AST/Interp/functions.cpp


Index: clang/test/AST/Interp/functions.cpp
===
--- clang/test/AST/Interp/functions.cpp
+++ clang/test/AST/Interp/functions.cpp
@@ -65,3 +65,11 @@
   return recursion(i);
 }
 static_assert(recursion(10) == 0, "");
+
+
+template
+constexpr decltype(N) getNum() {
+  return N;
+}
+static_assert(getNum<-2>() == -2, "");
+static_assert(getNum<10>() == 10, "");
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -68,6 +68,7 @@
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
   bool VisitInitListExpr(const InitListExpr *E);
   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
+  bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr 
*E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -267,6 +267,12 @@
   return false;
 }
 
+template 
+bool ByteCodeExprGen::VisitSubstNonTypeTemplateParmExpr(
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);


Index: clang/test/AST/Interp/functions.cpp
===
--- clang/test/AST/Interp/functions.cpp
+++ clang/test/AST/Interp/functions.cpp
@@ -65,3 +65,11 @@
   return recursion(i);
 }
 static_assert(recursion(10) == 0, "");
+
+
+template
+constexpr decltype(N) getNum() {
+  return N;
+}
+static_assert(getNum<-2>() == -2, "");
+static_assert(getNum<10>() == 10, "");
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -68,6 +68,7 @@
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
   bool VisitInitListExpr(const InitListExpr *E);
   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
+  bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -267,6 +267,12 @@
   return false;
 }
 
+template 
+bool ByteCodeExprGen::VisitSubstNonTypeTemplateParmExpr(
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132832: [clang][Interp] Handle missing local initializers better

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, shafik, erichkeane, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This is illegal in a constexpr context. We can already figure that out,
but we'd still run into an assertion later on when trying to visit the
missing initializer or run the invalid function.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132832

Files:
  clang/lib/AST/Interp/ByteCodeEmitter.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Function.h
  clang/test/AST/Interp/cxx20.cpp

Index: clang/test/AST/Interp/cxx20.cpp
===
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -2,8 +2,6 @@
 // RUN: %clang_cc1 -std=c++20 -verify=ref %s
 
 
-// expected-no-diagnostics
-// ref-no-diagnostics
 constexpr int getMinus5() {
   int a = 10;
   a = -5;
@@ -53,3 +51,12 @@
   return v;
 }
 //static_assert(pointerAssign2() == 12, ""); TODO
+
+
+constexpr int unInitLocal() {
+  int a;
+  return a; // ref-note{{read of uninitialized object}}
+}
+static_assert(unInitLocal() == 0, ""); // expected-error {{not an integral constant expression}} \
+   // ref-error {{not an integral constant expression}} \
+   // ref-note {{in call to 'unInitLocal()'}}
Index: clang/lib/AST/Interp/Function.h
===
--- clang/lib/AST/Interp/Function.h
+++ clang/lib/AST/Interp/Function.h
@@ -112,6 +112,9 @@
   /// Checks if the function is a constructor.
   bool isConstructor() const { return isa(F); }
 
+  /// Checks if the function is fully done compiling.
+  bool isFullyCompiled() const { return IsFullyCompiled; }
+
 private:
   /// Construct a function representing an actual function.
   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
@@ -128,6 +131,8 @@
 IsValid = true;
   }
 
+  void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
+
 private:
   friend class Program;
   friend class ByteCodeEmitter;
@@ -154,6 +159,9 @@
   llvm::DenseMap Params;
   /// Flag to indicate if the function is valid.
   bool IsValid = false;
+  /// Flag to indicate if the function is done being
+  /// compile to bytecode.
+  bool IsFullyCompiled = false;
 
 public:
   /// Dumps the disassembled bytecode to \c llvm::errs().
Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -238,12 +238,17 @@
 
   // Integers, pointers, primitives.
   if (Optional T = this->classify(VD->getType())) {
+const Expr *Init = VD->getInit();
 auto Offset =
 this->allocateLocalPrimitive(VD, *T, VD->getType().isConstQualified());
+
+if (!Init)
+  return false;
+
 // Compile the initialiser in its own scope.
-{
+if (Init) {
   ExprScope Scope(this);
-  if (!this->visit(VD->getInit()))
+  if (!this->visit(Init))
 return false;
 }
 // Set the value.
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -699,6 +699,14 @@
 }
 assert(Func);
 
+// If the function is being compiled right now, this is a recursive call.
+// In that case, the function can't be valid yet, even though it will be
+// later.
+// If the function is already fully compiled but not constexpr, it was
+// found to be faulty earlier on, so bail out.
+if (Func->isFullyCompiled() && !Func->isConstexpr())
+  return false;
+
 QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
 Optional T = classify(ReturnType);
 
Index: clang/lib/AST/Interp/ByteCodeEmitter.cpp
===
--- clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -62,8 +62,10 @@
 // Return a dummy function if compilation failed.
 if (BailLocation)
   return llvm::make_error(*BailLocation);
-else
+else {
+  Func->setIsFullyCompiled(true);
   return Func;
+}
   } else {
 // Create scopes from descriptors.
 llvm::SmallVector Scopes;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132832: [clang][Interp] Handle missing local initializers better

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 456281.

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

https://reviews.llvm.org/D132832

Files:
  clang/lib/AST/Interp/ByteCodeEmitter.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Function.h
  clang/test/AST/Interp/cxx20.cpp

Index: clang/test/AST/Interp/cxx20.cpp
===
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -2,8 +2,6 @@
 // RUN: %clang_cc1 -std=c++20 -verify=ref %s
 
 
-// expected-no-diagnostics
-// ref-no-diagnostics
 constexpr int getMinus5() {
   int a = 10;
   a = -5;
@@ -53,3 +51,12 @@
   return v;
 }
 //static_assert(pointerAssign2() == 12, ""); TODO
+
+
+constexpr int unInitLocal() {
+  int a;
+  return a; // ref-note{{read of uninitialized object}}
+}
+static_assert(unInitLocal() == 0, ""); // expected-error {{not an integral constant expression}} \
+   // ref-error {{not an integral constant expression}} \
+   // ref-note {{in call to 'unInitLocal()'}}
Index: clang/lib/AST/Interp/Function.h
===
--- clang/lib/AST/Interp/Function.h
+++ clang/lib/AST/Interp/Function.h
@@ -112,6 +112,9 @@
   /// Checks if the function is a constructor.
   bool isConstructor() const { return isa(F); }
 
+  /// Checks if the function is fully done compiling.
+  bool isFullyCompiled() const { return IsFullyCompiled; }
+
 private:
   /// Construct a function representing an actual function.
   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
@@ -128,6 +131,8 @@
 IsValid = true;
   }
 
+  void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
+
 private:
   friend class Program;
   friend class ByteCodeEmitter;
@@ -154,6 +159,9 @@
   llvm::DenseMap Params;
   /// Flag to indicate if the function is valid.
   bool IsValid = false;
+  /// Flag to indicate if the function is done being
+  /// compile to bytecode.
+  bool IsFullyCompiled = false;
 
 public:
   /// Dumps the disassembled bytecode to \c llvm::errs().
Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -238,12 +238,17 @@
 
   // Integers, pointers, primitives.
   if (Optional T = this->classify(VD->getType())) {
+const Expr *Init = VD->getInit();
 auto Offset =
 this->allocateLocalPrimitive(VD, *T, VD->getType().isConstQualified());
+
+if (!Init)
+  return false;
+
 // Compile the initialiser in its own scope.
-{
+if (Init) {
   ExprScope Scope(this);
-  if (!this->visit(VD->getInit()))
+  if (!this->visit(Init))
 return false;
 }
 // Set the value.
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -699,6 +699,14 @@
 }
 assert(Func);
 
+// If the function is being compiled right now, this is a recursive call.
+// In that case, the function can't be valid yet, even though it will be
+// later.
+// If the function is already fully compiled but not constexpr, it was
+// found to be faulty earlier on, so bail out.
+if (Func->isFullyCompiled() && !Func->isConstexpr())
+  return false;
+
 QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
 Optional T = classify(ReturnType);
 
Index: clang/lib/AST/Interp/ByteCodeEmitter.cpp
===
--- clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -62,8 +62,10 @@
 // Return a dummy function if compilation failed.
 if (BailLocation)
   return llvm::make_error(*BailLocation);
-else
+else {
+  Func->setIsFullyCompiled(true);
   return Func;
+}
   } else {
 // Create scopes from descriptors.
 llvm::SmallVector Scopes;
@@ -74,6 +76,7 @@
 // Set the function's code.
 Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
   std::move(Scopes));
+Func->setIsFullyCompiled(true);
 return Func;
   }
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132832: [clang][Interp] Handle missing local initializers better

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/ByteCodeStmtGen.cpp:245
+
+if (!Init)
+  return false;

erichkeane wrote:
> Would be nice to test this before the work to allocate Offset?
Ah, sure. Good catch.


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

https://reviews.llvm.org/D132832

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


[PATCH] D132832: [clang][Interp] Handle missing local initializers better

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 456328.
tbaeder marked 2 inline comments as done.

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

https://reviews.llvm.org/D132832

Files:
  clang/lib/AST/Interp/ByteCodeEmitter.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Function.h
  clang/test/AST/Interp/cxx20.cpp

Index: clang/test/AST/Interp/cxx20.cpp
===
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -2,8 +2,6 @@
 // RUN: %clang_cc1 -std=c++20 -verify=ref %s
 
 
-// expected-no-diagnostics
-// ref-no-diagnostics
 constexpr int getMinus5() {
   int a = 10;
   a = -5;
@@ -53,3 +51,12 @@
   return v;
 }
 //static_assert(pointerAssign2() == 12, ""); TODO
+
+
+constexpr int unInitLocal() {
+  int a;
+  return a; // ref-note{{read of uninitialized object}}
+}
+static_assert(unInitLocal() == 0, ""); // expected-error {{not an integral constant expression}} \
+   // ref-error {{not an integral constant expression}} \
+   // ref-note {{in call to 'unInitLocal()'}}
Index: clang/lib/AST/Interp/Function.h
===
--- clang/lib/AST/Interp/Function.h
+++ clang/lib/AST/Interp/Function.h
@@ -112,6 +112,9 @@
   /// Checks if the function is a constructor.
   bool isConstructor() const { return isa(F); }
 
+  /// Checks if the function is fully done compiling.
+  bool isFullyCompiled() const { return IsFullyCompiled; }
+
 private:
   /// Construct a function representing an actual function.
   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
@@ -128,6 +131,8 @@
 IsValid = true;
   }
 
+  void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
+
 private:
   friend class Program;
   friend class ByteCodeEmitter;
@@ -154,6 +159,9 @@
   llvm::DenseMap Params;
   /// Flag to indicate if the function is valid.
   bool IsValid = false;
+  /// Flag to indicate if the function is done being
+  /// compiled to bytecode.
+  bool IsFullyCompiled = false;
 
 public:
   /// Dumps the disassembled bytecode to \c llvm::errs().
Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -238,12 +238,18 @@
 
   // Integers, pointers, primitives.
   if (Optional T = this->classify(VD->getType())) {
+const Expr *Init = VD->getInit();
+
+if (!Init)
+  return false;
+
 auto Offset =
 this->allocateLocalPrimitive(VD, *T, VD->getType().isConstQualified());
-// Compile the initialiser in its own scope.
+
+// Compile the initializer in its own scope.
 {
   ExprScope Scope(this);
-  if (!this->visit(VD->getInit()))
+  if (!this->visit(Init))
 return false;
 }
 // Set the value.
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -699,6 +699,14 @@
 }
 assert(Func);
 
+// If the function is being compiled right now, this is a recursive call.
+// In that case, the function can't be valid yet, even though it will be
+// later.
+// If the function is already fully compiled but not constexpr, it was
+// found to be faulty earlier on, so bail out.
+if (Func->isFullyCompiled() && !Func->isConstexpr())
+  return false;
+
 QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
 Optional T = classify(ReturnType);
 
Index: clang/lib/AST/Interp/ByteCodeEmitter.cpp
===
--- clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -62,8 +62,10 @@
 // Return a dummy function if compilation failed.
 if (BailLocation)
   return llvm::make_error(*BailLocation);
-else
+else {
+  Func->setIsFullyCompiled(true);
   return Func;
+}
   } else {
 // Create scopes from descriptors.
 llvm::SmallVector Scopes;
@@ -74,6 +76,7 @@
 // Set the function's code.
 Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
   std::move(Scopes));
+Func->setIsFullyCompiled(true);
 return Func;
   }
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132821: [clang][Parse] Fix crash when emitting template diagnostic

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/test/Parser/cxx-concept-declaration.cpp:3
 // Support parsing of concepts
 // Disabled for now.
 

I guess we can drop these two lines now.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132821

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


[PATCH] D132821: [clang][Parse] Fix crash when emitting template diagnostic

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/include/clang/Basic/DiagnosticParseKinds.td:779
+  "|refers to a variable template||refers to a concept|"
+  "refers to a concept template}1">;
 def err_id_after_template_in_nested_name_spec : Error<

cjdb wrote:
> Is "concept template" a term of art? I have never heard of that before.
The enum member is called `clang::TNK_Concept_template`, so I made up "concept 
template" from that. Not sure what to use instead, would just "refers to a 
concept" be better?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132821

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


[PATCH] D132831: [clang][Interp] Handle SubstNonTypeTemplateParmExprs

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:273
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}

erichkeane wrote:
> Is there nothing special that has to happen when these are reference 
> parameters?  Can you at least add a test for that?
Umm, I don't really do references yet (I haven't tested them at all and I don't 
think they are implemented).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132831

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


[PATCH] D132727: [clang][Interp] Implement array initializers and subscript expressions

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 456376.

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

https://reviews.llvm.org/D132727

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/Pointer.cpp
  clang/lib/AST/Interp/Program.cpp
  clang/test/AST/Interp/arrays.cpp

Index: clang/test/AST/Interp/arrays.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/arrays.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+constexpr int m = 3;
+constexpr const int *foo[][5] = {
+  {nullptr, &m, nullptr, nullptr, nullptr},
+  {nullptr, nullptr, &m, nullptr, nullptr},
+  {nullptr, nullptr, nullptr, &m, nullptr},
+};
+
+static_assert(foo[0][0] == nullptr, "");
+static_assert(foo[0][1] == &m, "");
+static_assert(foo[0][2] == nullptr, "");
+static_assert(foo[0][3] == nullptr, "");
+static_assert(foo[0][4] == nullptr, "");
+static_assert(foo[1][0] == nullptr, "");
+static_assert(foo[1][1] == nullptr, "");
+static_assert(foo[1][2] == &m, "");
+static_assert(foo[1][3] == nullptr, "");
+static_assert(foo[1][4] == nullptr, "");
+static_assert(foo[2][0] == nullptr, "");
+static_assert(foo[2][1] == nullptr, "");
+static_assert(foo[2][2] == nullptr, "");
+static_assert(foo[2][3] == &m, "");
+static_assert(foo[2][4] == nullptr, "");
+
+
+/// A init list for a primitive value.
+constexpr int f{5};
+static_assert(f == 5, "");
+
+
+constexpr int getElement(int i) {
+  int values[] = {1, 4, 9, 16, 25, 36};
+  return values[i];
+}
+static_assert(getElement(1) == 4, "");
+static_assert(getElement(5) == 36, "");
+
+
+template
+constexpr T getElementOf(T* array, int i) {
+  return array[i];
+}
+static_assert(getElementOf(foo[0], 1) == &m, "");
+
+
+constexpr int data[] = {5, 4, 3, 2, 1};
+static_assert(data[0] == 4, ""); // expected-error{{failed}} \
+ // expected-note{{5 == 4}} \
+ // ref-error{{failed}} \
+ // ref-note{{5 == 4}}
+
+
+constexpr int dynamic[] = {
+  f, 3, 2 + 5, data[3], *getElementOf(foo[2], 3)
+};
+static_assert(dynamic[0] == f, "");
+static_assert(dynamic[3] == 2, "");
+
+
+constexpr int dependent[4] = {
+  0, 1, dependent[0], dependent[1]
+};
+static_assert(dependent[2] == dependent[0], "");
+static_assert(dependent[3] == dependent[1], "");
+
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#pragma clang diagnostic ignored "-Winitializer-overrides"
+constexpr int DI[] = {
+  [0] = 10,
+  [1] = 20,
+  30,
+  40,
+  [1] = 50
+};
+static_assert(DI[0] == 10, "");
+static_assert(DI[1] == 50, "");
+static_assert(DI[2] == 30, "");
+static_assert(DI[3] == 40, "");
+#pragma clang diagnostic pop
Index: clang/lib/AST/Interp/Program.cpp
===
--- clang/lib/AST/Interp/Program.cpp
+++ clang/lib/AST/Interp/Program.cpp
@@ -334,14 +334,15 @@
   } else {
 // Arrays of composites. In this case, the array is a list of pointers,
 // followed by the actual elements.
-Descriptor *Desc =
+Descriptor *ElemDesc =
 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
-if (!Desc)
+if (!ElemDesc)
   return nullptr;
-InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
+InterpSize ElemSize =
+ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
 if (std::numeric_limits::max() / ElemSize <= NumElems)
   return {};
-return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
+return allocateDescriptor(D, ElemDesc, NumElems, IsConst, IsTemporary,
   IsMutable);
   }
 }
Index: clang/lib/AST/Interp/Pointer.cpp
===
--- clang/lib/AST/Interp/Pointer.cpp
+++ clang/lib/AST/Interp/Pointer.cpp
@@ -106,7 +106,7 @@
 
   // Build the path into the object.
   Pointer Ptr = *this;
-  while (Ptr.isField()) {
+  while (Ptr.isField() || Ptr.isArrayElement()) {
 if (Ptr.isArrayElement()) {
   Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
   Ptr = Ptr.getArray();
@@ -154,7 +154,8 @@
 void Pointer::initialize() const {
   assert(Pointee && "Cannot initialize null pointer");
   Descriptor *Desc = getFieldDesc();
-  if (Desc->isPrimitiveArray()) {
+
+  if (Desc->isArray() || Desc->isPrimitiveArray()) {
 if (!Pointee->IsStatic) {
   // Primitive array initializer.
   InitMap *&Map = getInitMap();
Index: clang/lib/AST/Interp/Interp.h
===
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Inter

[PATCH] D132727: [clang][Interp] Implement array initializers and subscript expressions

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

In D132727#3755571 , @aaron.ballman 
wrote:

> Precommit CI found a relevant failure:

That needs the lvalue-to-rvalue conversion patch first.


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

https://reviews.llvm.org/D132727

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


[PATCH] D132821: [clang][Parse] Fix crash when emitting template diagnostic

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 456389.
tbaeder marked 3 inline comments as done.

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

https://reviews.llvm.org/D132821

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/test/Parser/cxx-concept-declaration.cpp


Index: clang/test/Parser/cxx-concept-declaration.cpp
===
--- clang/test/Parser/cxx-concept-declaration.cpp
+++ clang/test/Parser/cxx-concept-declaration.cpp
@@ -1,7 +1,12 @@
 
 // Support parsing of concepts
 // Disabled for now.
-// expected-no-diagnostics
 
-// RUN:  %clang_cc1 -std=c++14 -x c++ -verify %s
-// template concept C1 = true;
+// RUN:  %clang_cc1 -std=c++20 -x c++ -verify %s
+template concept C1 = true;
+
+template
+concept C = true;
+
+template
+class C {}; //expected-error{{identifier followed by '<' indicates a 
class template specialization but 'C' refers to a concept}}
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -775,7 +775,8 @@
 def err_template_spec_syntax_non_template : Error<
   "identifier followed by '<' indicates a class template specialization but "
   "%0 %select{does not refer to a template|refers to a function template|"
-  "|refers to a variable template||refers to a concept}1">;
+  "|refers to a variable template|||"
+  "refers to a concept}1">;
 def err_id_after_template_in_nested_name_spec : Error<
   "expected template name after 'template' keyword in nested name specifier">;
 def err_unexpected_template_in_unqualified_id : Error<


Index: clang/test/Parser/cxx-concept-declaration.cpp
===
--- clang/test/Parser/cxx-concept-declaration.cpp
+++ clang/test/Parser/cxx-concept-declaration.cpp
@@ -1,7 +1,12 @@
 
 // Support parsing of concepts
 // Disabled for now.
-// expected-no-diagnostics
 
-// RUN:  %clang_cc1 -std=c++14 -x c++ -verify %s
-// template concept C1 = true;
+// RUN:  %clang_cc1 -std=c++20 -x c++ -verify %s
+template concept C1 = true;
+
+template
+concept C = true;
+
+template
+class C {}; //expected-error{{identifier followed by '<' indicates a class template specialization but 'C' refers to a concept}}
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -775,7 +775,8 @@
 def err_template_spec_syntax_non_template : Error<
   "identifier followed by '<' indicates a class template specialization but "
   "%0 %select{does not refer to a template|refers to a function template|"
-  "|refers to a variable template||refers to a concept}1">;
+  "|refers to a variable template|||"
+  "refers to a concept}1">;
 def err_id_after_template_in_nested_name_spec : Error<
   "expected template name after 'template' keyword in nested name specifier">;
 def err_unexpected_template_in_unqualified_id : Error<
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132831: [clang][Interp] Handle SubstNonTypeTemplateParmExprs

2022-08-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:273
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}

tahonermann wrote:
> erichkeane wrote:
> > tbaeder wrote:
> > > erichkeane wrote:
> > > > Is there nothing special that has to happen when these are reference 
> > > > parameters?  Can you at least add a test for that?
> > > Umm, I don't really do references yet (I haven't tested them at all and I 
> > > don't think they are implemented).
> > Hmm... that is unfortunate.  We really should be doing references ASAP, as 
> > they are going to be a pretty critical/oft-needed during testing kinda 
> > thing.  I'd at least want a commented-out test that you can re-enable ASAP.
> Are not-yet-implemented features consistently implemented such that constant 
> evaluation will fail with a (possibly unhelpful) diagnostic? As in 
> https://godbolt.org/z/8vvdca9Ma? If so, can tests be added ahead of time with 
> annotations for expected errors (essentially false positives to be addressed 
> later)?
Some are always (like unhandled AST node), some are not.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132831

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


[PATCH] D132821: [clang][Parse] Fix crash when emitting template diagnostic

2022-08-30 Thread Timm Bäder via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGef1bb11a34de: [clang][Parse] Fix crash when emitting 
template diagnostic (authored by tbaeder).

Changed prior to commit:
  https://reviews.llvm.org/D132821?vs=456389&id=456643#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132821

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/test/Parser/cxx-concept-declaration.cpp


Index: clang/test/Parser/cxx-concept-declaration.cpp
===
--- clang/test/Parser/cxx-concept-declaration.cpp
+++ clang/test/Parser/cxx-concept-declaration.cpp
@@ -1,7 +1,12 @@
 
 // Support parsing of concepts
 // Disabled for now.
-// expected-no-diagnostics
 
-// RUN:  %clang_cc1 -std=c++14 -x c++ -verify %s
-// template concept C1 = true;
+// RUN:  %clang_cc1 -std=c++20 -x c++ -verify %s
+template concept C1 = true;
+
+template
+concept C = true;
+
+template
+class C {}; //expected-error{{identifier followed by '<' indicates a 
class template specialization but 'C' refers to a concept}}
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -775,7 +775,8 @@
 def err_template_spec_syntax_non_template : Error<
   "identifier followed by '<' indicates a class template specialization but "
   "%0 %select{does not refer to a template|refers to a function template|"
-  "|refers to a variable template||refers to a concept}1">;
+  "|refers to a variable template|||"
+  "refers to a concept}1">;
 def err_id_after_template_in_nested_name_spec : Error<
   "expected template name after 'template' keyword in nested name specifier">;
 def err_unexpected_template_in_unqualified_id : Error<
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -84,6 +84,8 @@
 - Fix assert that triggers a crash during template name lookup when a type was
   incomplete but was not also a TagType. This fixes
   `Issue 57387 `_.
+- Fix a crash when emitting a concept-related diagnostic. This fixes
+  `Issue 57415 `_.
 
 
 Improvements to Clang's diagnostics


Index: clang/test/Parser/cxx-concept-declaration.cpp
===
--- clang/test/Parser/cxx-concept-declaration.cpp
+++ clang/test/Parser/cxx-concept-declaration.cpp
@@ -1,7 +1,12 @@
 
 // Support parsing of concepts
 // Disabled for now.
-// expected-no-diagnostics
 
-// RUN:  %clang_cc1 -std=c++14 -x c++ -verify %s
-// template concept C1 = true;
+// RUN:  %clang_cc1 -std=c++20 -x c++ -verify %s
+template concept C1 = true;
+
+template
+concept C = true;
+
+template
+class C {}; //expected-error{{identifier followed by '<' indicates a class template specialization but 'C' refers to a concept}}
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -775,7 +775,8 @@
 def err_template_spec_syntax_non_template : Error<
   "identifier followed by '<' indicates a class template specialization but "
   "%0 %select{does not refer to a template|refers to a function template|"
-  "|refers to a variable template||refers to a concept}1">;
+  "|refers to a variable template|||"
+  "refers to a concept}1">;
 def err_id_after_template_in_nested_name_spec : Error<
   "expected template name after 'template' keyword in nested name specifier">;
 def err_unexpected_template_in_unqualified_id : Error<
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -84,6 +84,8 @@
 - Fix assert that triggers a crash during template name lookup when a type was
   incomplete but was not also a TagType. This fixes
   `Issue 57387 `_.
+- Fix a crash when emitting a concept-related diagnostic. This fixes
+  `Issue 57415 `_.
 
 
 Improvements to Clang's diagnostics
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132997: [clang][Interp] Handle DeclRefExpr of reference types

2022-08-31 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, shafik, erichkeane, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

And add a couple of tests for it.

Notably, this is missing `MaterializeTemporaryExpr` and `ExprWithCleanups`, but 
the basic support seems to work.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132997

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/test/AST/Interp/references.cpp

Index: clang/test/AST/Interp/references.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/references.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+constexpr int a = 10;
+constexpr const int &b = a;
+static_assert(a == b, "");
+
+constexpr int assignToReference() {
+  int a = 20;
+  int &b =a;
+
+  b = 100;
+  return a;
+}
+static_assert(assignToReference() == 100, "");
+
+
+constexpr void setValue(int &dest, int val) {
+  dest = val;
+}
+
+constexpr int checkSetValue() {
+  int l = 100;
+  setValue(l, 200);
+  return l;
+}
+static_assert(checkSetValue() == 200, "");
+
+constexpr int readLocalRef() {
+  int a = 20;
+  int &b = a;
+  return b;
+}
+static_assert(readLocalRef() == 20, "");
+
+constexpr int incRef() {
+  int a = 0;
+  int &b = a;
+
+  b = b + 1;
+
+  return a;
+}
+static_assert(incRef() == 1, "");
+
+
+template
+constexpr void Plus3(int &A) {
+  A = V + 3;
+}
+constexpr int foo = 4;
+
+constexpr int callTemplate() {
+  int a = 3;
+  Plus3(a);
+  return a;
+}
+static_assert(callTemplate() == 7, "");
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -845,15 +845,38 @@
 template 
 bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) {
   const auto *Decl = E->getDecl();
+  bool IsReference = Decl->getType()->isReferenceType();
+  bool FoundDecl = false;
 
   if (auto It = Locals.find(Decl); It != Locals.end()) {
 const unsigned Offset = It->second.Offset;
-return this->emitGetPtrLocal(Offset, E);
+if (!this->emitGetPtrLocal(Offset, E))
+  return false;
+
+FoundDecl = true;
   } else if (auto GlobalIndex = P.getGlobal(Decl)) {
-return this->emitGetPtrGlobal(*GlobalIndex, E);
+if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+  return false;
+
+FoundDecl = true;
   } else if (const auto *PVD = dyn_cast(Decl)) {
-if (auto It = this->Params.find(PVD); It != this->Params.end())
-  return this->emitGetPtrParam(It->second, E);
+if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+  if (!this->emitGetPtrParam(It->second, E))
+return false;
+
+  FoundDecl = true;
+}
+  }
+
+  // References are implemented using pointers, so when we get here,
+  // we have a pointer to a pointer, which we need to de-reference once.
+  if (FoundDecl) {
+if (IsReference) {
+  if (!this->emitLoadPop(PT_Ptr, E))
+return false;
+}
+
+return true;
   }
 
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132136: [clang] Perform implicit lvalue-to-rvalue cast with new interpreter

2022-08-31 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

In D132136#3755724 , @aaron.ballman 
wrote:

> In D132136#3753290 , @tbaeder wrote:
>
>> In D132136#3751702 , @erichkeane 
>> wrote:
>>
>>> Would be great if we had a better test here... is there anything we can do 
>>> to validate this is happening other than checking for that one note?
>>
>> `EvaluateAsRValue` is called from `Expr::EvaluateAsRValue()`, so I think it 
>> would be possible to write a unittest for this. But I think that would be a 
>> lot of effort just to test this. There is even 
>> `unittests/AST/EvaluateAsRValueTest.cpp` already, but it tests the wrong 
>> thing :(
>
> The existing test coverage being wrong seems like all the more reason to add 
> correct test coverage. LValue to RValue conversions are important to get 
> right (lol here's a wonderful demonstration of where we didn't bother to see 
> if we got it right that I accidentally stumbled into when trying to give you 
> a constexpr test case: https://godbolt.org/z/bdxbers3M), especially because 
> they're going to impact which overload gets called when picking between an 
> `&&` and `&` overload.

To be clear, can I land this patch without the unittest? I tried adding this to 
`EvaluateAsRValueTest.cpp` but I just run into other problems in the new 
interpreter :) So more unittests would definitely be good.


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

https://reviews.llvm.org/D132136

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


[PATCH] D132829: [clang][Interp] Handle ImplictValueInitExprs

2022-08-31 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 456915.

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

https://reviews.llvm.org/D132829

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Opcodes.td
  clang/test/AST/Interp/arrays.cpp


Index: clang/test/AST/Interp/arrays.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/arrays.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+/// expected-no-diagnostics
+/// ref-no-diagnostics
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#pragma clang diagnostic ignored "-Winitializer-overrides"
+/// FIXME: The example below tests ImplicitValueInitExprs, but we can't
+///   currently evaluate other parts of it.
+#if 0
+struct fred {
+  char s [6];
+  int n;
+};
+
+struct fred y [] = { [0] = { .s[0] = 'q' } };
+#endif
+#pragma clang diagnostic pop
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -203,6 +203,7 @@
 // [] -> [Integer]
 def Zero : Opcode {
   let Types = [AluTypeClass];
+  let HasGroup = 1;
 }
 
 // [] -> [Pointer]
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -75,6 +75,7 @@
   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
+  bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -223,6 +223,14 @@
   return this->bail(BO);
 }
 
+template 
+bool ByteCodeExprGen::VisitImplicitValueInitExpr(const 
ImplicitValueInitExpr *E) {
+  if (Optional T = classify(E))
+return this->emitZero(*T, E);
+
+  return false;
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);


Index: clang/test/AST/Interp/arrays.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/arrays.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+/// expected-no-diagnostics
+/// ref-no-diagnostics
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#pragma clang diagnostic ignored "-Winitializer-overrides"
+/// FIXME: The example below tests ImplicitValueInitExprs, but we can't
+///   currently evaluate other parts of it.
+#if 0
+struct fred {
+  char s [6];
+  int n;
+};
+
+struct fred y [] = { [0] = { .s[0] = 'q' } };
+#endif
+#pragma clang diagnostic pop
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -203,6 +203,7 @@
 // [] -> [Integer]
 def Zero : Opcode {
   let Types = [AluTypeClass];
+  let HasGroup = 1;
 }
 
 // [] -> [Pointer]
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -75,6 +75,7 @@
   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
+  bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -223,6 +223,14 @@
   return this->bail(BO);
 }
 
+template 
+bool ByteCodeExprGen::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+  if (Optional T = classify(E))
+return this->emitZero(*T, E);
+
+  return false;
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132997: [clang][Interp] Handle DeclRefExpr of reference types

2022-08-31 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 456917.

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

https://reviews.llvm.org/D132997

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/test/AST/Interp/references.cpp

Index: clang/test/AST/Interp/references.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/references.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+constexpr int a = 10;
+constexpr const int &b = a;
+static_assert(a == b, "");
+
+constexpr int assignToReference() {
+  int a = 20;
+  int &b =a;
+
+  b = 100;
+  return a;
+}
+static_assert(assignToReference() == 100, "");
+
+
+constexpr void setValue(int &dest, int val) {
+  dest = val;
+}
+
+constexpr int checkSetValue() {
+  int l = 100;
+  setValue(l, 200);
+  return l;
+}
+static_assert(checkSetValue() == 200, "");
+
+constexpr int readLocalRef() {
+  int a = 20;
+  int &b = a;
+  return b;
+}
+static_assert(readLocalRef() == 20, "");
+
+constexpr int incRef() {
+  int a = 0;
+  int &b = a;
+
+  b = b + 1;
+
+  return a;
+}
+static_assert(incRef() == 1, "");
+
+
+template
+constexpr void Plus3(int &A) {
+  A = V + 3;
+}
+constexpr int foo = 4;
+
+constexpr int callTemplate() {
+  int a = 3;
+  Plus3(a);
+  return a;
+}
+static_assert(callTemplate() == 7, "");
+
+
+constexpr int& getValue(int *array, int index) {
+  return array[index];
+}
+constexpr int testGetValue() {
+  int values[] = {1, 2, 3, 4};
+  getValue(values, 2) = 30;
+  return values[2];
+}
+static_assert(testGetValue() == 30, "");
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -845,15 +845,38 @@
 template 
 bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) {
   const auto *Decl = E->getDecl();
+  bool IsReference = Decl->getType()->isReferenceType();
+  bool FoundDecl = false;
 
   if (auto It = Locals.find(Decl); It != Locals.end()) {
 const unsigned Offset = It->second.Offset;
-return this->emitGetPtrLocal(Offset, E);
+if (!this->emitGetPtrLocal(Offset, E))
+  return false;
+
+FoundDecl = true;
   } else if (auto GlobalIndex = P.getGlobal(Decl)) {
-return this->emitGetPtrGlobal(*GlobalIndex, E);
+if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+  return false;
+
+FoundDecl = true;
   } else if (const auto *PVD = dyn_cast(Decl)) {
-if (auto It = this->Params.find(PVD); It != this->Params.end())
-  return this->emitGetPtrParam(It->second, E);
+if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+  if (!this->emitGetPtrParam(It->second, E))
+return false;
+
+  FoundDecl = true;
+}
+  }
+
+  // References are implemented using pointers, so when we get here,
+  // we have a pointer to a pointer, which we need to de-reference once.
+  if (FoundDecl) {
+if (IsReference) {
+  if (!this->emitLoadPop(PT_Ptr, E))
+return false;
+}
+
+return true;
   }
 
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132997: [clang][Interp] Handle DeclRefExpr of reference types

2022-08-31 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 456944.

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

https://reviews.llvm.org/D132997

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/test/AST/Interp/arrays.cpp
  clang/test/AST/Interp/references.cpp

Index: clang/test/AST/Interp/references.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/references.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+constexpr int a = 10;
+constexpr const int &b = a;
+static_assert(a == b, "");
+
+constexpr int assignToReference() {
+  int a = 20;
+  int &b =a;
+
+  b = 100;
+  return a;
+}
+static_assert(assignToReference() == 100, "");
+
+
+constexpr void setValue(int &dest, int val) {
+  dest = val;
+}
+
+constexpr int checkSetValue() {
+  int l = 100;
+  setValue(l, 200);
+  return l;
+}
+static_assert(checkSetValue() == 200, "");
+
+constexpr int readLocalRef() {
+  int a = 20;
+  int &b = a;
+  return b;
+}
+static_assert(readLocalRef() == 20, "");
+
+constexpr int incRef() {
+  int a = 0;
+  int &b = a;
+
+  b = b + 1;
+
+  return a;
+}
+static_assert(incRef() == 1, "");
+
+
+template
+constexpr void Plus3(int &A) {
+  A = V + 3;
+}
+constexpr int foo = 4;
+
+constexpr int callTemplate() {
+  int a = 3;
+  Plus3(a);
+  return a;
+}
+static_assert(callTemplate() == 7, "");
+
+
+constexpr int& getValue(int *array, int index) {
+  return array[index];
+}
+constexpr int testGetValue() {
+  int values[] = {1, 2, 3, 4};
+  getValue(values, 2) = 30;
+  return values[2];
+}
+static_assert(testGetValue() == 30, "");
Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -45,6 +45,13 @@
 static_assert(getElementOf(foo[0], 1) == &m, "");
 
 
+template 
+constexpr T& getElementOfArray(T (&array)[N], int I) {
+  return array[I];
+}
+static_assert(getElementOfArray(foo[2], 3) == &m, "");
+
+
 constexpr int data[] = {5, 4, 3, 2, 1};
 static_assert(data[0] == 4, ""); // expected-error{{failed}} \
  // expected-note{{5 == 4}} \
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -845,15 +845,38 @@
 template 
 bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) {
   const auto *Decl = E->getDecl();
+  bool IsReference = Decl->getType()->isReferenceType();
+  bool FoundDecl = false;
 
   if (auto It = Locals.find(Decl); It != Locals.end()) {
 const unsigned Offset = It->second.Offset;
-return this->emitGetPtrLocal(Offset, E);
+if (!this->emitGetPtrLocal(Offset, E))
+  return false;
+
+FoundDecl = true;
   } else if (auto GlobalIndex = P.getGlobal(Decl)) {
-return this->emitGetPtrGlobal(*GlobalIndex, E);
+if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+  return false;
+
+FoundDecl = true;
   } else if (const auto *PVD = dyn_cast(Decl)) {
-if (auto It = this->Params.find(PVD); It != this->Params.end())
-  return this->emitGetPtrParam(It->second, E);
+if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+  if (!this->emitGetPtrParam(It->second, E))
+return false;
+
+  FoundDecl = true;
+}
+  }
+
+  // References are implemented using pointers, so when we get here,
+  // we have a pointer to a pointer, which we need to de-reference once.
+  if (FoundDecl) {
+if (IsReference) {
+  if (!this->emitLoadPop(PT_Ptr, E))
+return false;
+}
+
+return true;
   }
 
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132727: [clang][Interp] Implement array initializers and subscript expressions

2022-08-31 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder marked an inline comment as done.
tbaeder added inline comments.



Comment at: clang/test/AST/Interp/arrays.cpp:41-44
+template
+constexpr T getElementOf(T* array, int i) {
+  return array[i];
+}

aaron.ballman wrote:
> A similar test we might want to add (whenever we get around to references):
> ```
> template 
> constexpr T& getElementOf(T (&array)[N], int I) {
>   return array[I];
> }
> static_assert(getElementOf(foo[2], 3) == &m, "");
> ```
I added that to https://reviews.llvm.org/D132997


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

https://reviews.llvm.org/D132727

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


[PATCH] D132727: [clang][Interp] Implement array initializers and subscript expressions

2022-08-31 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 456953.
tbaeder marked an inline comment as done.

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

https://reviews.llvm.org/D132727

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/Pointer.cpp
  clang/lib/AST/Interp/Program.cpp
  clang/test/AST/Interp/arrays.cpp

Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -1,13 +1,85 @@
 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
 // RUN: %clang_cc1 -verify=ref %s
 
+constexpr int m = 3;
+constexpr const int *foo[][5] = {
+  {nullptr, &m, nullptr, nullptr, nullptr},
+  {nullptr, nullptr, &m, nullptr, nullptr},
+  {nullptr, nullptr, nullptr, &m, nullptr},
+};
+
+static_assert(foo[0][0] == nullptr, "");
+static_assert(foo[0][1] == &m, "");
+static_assert(foo[0][2] == nullptr, "");
+static_assert(foo[0][3] == nullptr, "");
+static_assert(foo[0][4] == nullptr, "");
+static_assert(foo[1][0] == nullptr, "");
+static_assert(foo[1][1] == nullptr, "");
+static_assert(foo[1][2] == &m, "");
+static_assert(foo[1][3] == nullptr, "");
+static_assert(foo[1][4] == nullptr, "");
+static_assert(foo[2][0] == nullptr, "");
+static_assert(foo[2][1] == nullptr, "");
+static_assert(foo[2][2] == nullptr, "");
+static_assert(foo[2][3] == &m, "");
+static_assert(foo[2][4] == nullptr, "");
+
+
+/// A init list for a primitive value.
+constexpr int f{5};
+static_assert(f == 5, "");
+
+
+constexpr int getElement(int i) {
+  int values[] = {1, 4, 9, 16, 25, 36};
+  return values[i];
+}
+static_assert(getElement(1) == 4, "");
+static_assert(getElement(5) == 36, "");
+
+
+template
+constexpr T getElementOf(T* array, int i) {
+  return array[i];
+}
+static_assert(getElementOf(foo[0], 1) == &m, "");
+
 
-/// expected-no-diagnostics
-/// ref-no-diagnostics
+constexpr int data[] = {5, 4, 3, 2, 1};
+static_assert(data[0] == 4, ""); // expected-error{{failed}} \
+ // expected-note{{5 == 4}} \
+ // ref-error{{failed}} \
+ // ref-note{{5 == 4}}
+
+
+constexpr int dynamic[] = {
+  f, 3, 2 + 5, data[3], *getElementOf(foo[2], 3)
+};
+static_assert(dynamic[0] == f, "");
+static_assert(dynamic[3] == 2, "");
+
+
+constexpr int dependent[4] = {
+  0, 1, dependent[0], dependent[1]
+};
+static_assert(dependent[2] == dependent[0], "");
+static_assert(dependent[3] == dependent[1], "");
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wc99-extensions"
 #pragma clang diagnostic ignored "-Winitializer-overrides"
+constexpr int DI[] = {
+  [0] = 10,
+  [1] = 20,
+  30,
+  40,
+  [1] = 50
+};
+static_assert(DI[0] == 10, "");
+static_assert(DI[1] == 50, "");
+static_assert(DI[2] == 30, "");
+static_assert(DI[3] == 40, "");
+
 /// FIXME: The example below tests ImplicitValueInitExprs, but we can't
 ///   currently evaluate other parts of it.
 #if 0
Index: clang/lib/AST/Interp/Program.cpp
===
--- clang/lib/AST/Interp/Program.cpp
+++ clang/lib/AST/Interp/Program.cpp
@@ -334,14 +334,15 @@
   } else {
 // Arrays of composites. In this case, the array is a list of pointers,
 // followed by the actual elements.
-Descriptor *Desc =
+Descriptor *ElemDesc =
 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
-if (!Desc)
+if (!ElemDesc)
   return nullptr;
-InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
+InterpSize ElemSize =
+ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
 if (std::numeric_limits::max() / ElemSize <= NumElems)
   return {};
-return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
+return allocateDescriptor(D, ElemDesc, NumElems, IsConst, IsTemporary,
   IsMutable);
   }
 }
Index: clang/lib/AST/Interp/Pointer.cpp
===
--- clang/lib/AST/Interp/Pointer.cpp
+++ clang/lib/AST/Interp/Pointer.cpp
@@ -106,7 +106,7 @@
 
   // Build the path into the object.
   Pointer Ptr = *this;
-  while (Ptr.isField()) {
+  while (Ptr.isField() || Ptr.isArrayElement()) {
 if (Ptr.isArrayElement()) {
   Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
   Ptr = Ptr.getArray();
@@ -154,7 +154,8 @@
 void Pointer::initialize() const {
   assert(Pointee && "Cannot initialize null pointer");
   Descriptor *Desc = getFieldDesc();
-  if (Desc->isPrimitiveArray()) {
+
+  if (Desc->isArray() || Desc->isPrimitiveArray()) {
 if (!Pointee->IsStatic) {
   // Primitive arra

[PATCH] D132831: [clang][Interp] Handle SubstNonTypeTemplateParmExprs

2022-09-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder marked 3 inline comments as done.
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:273
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}

tbaeder wrote:
> tahonermann wrote:
> > erichkeane wrote:
> > > tbaeder wrote:
> > > > erichkeane wrote:
> > > > > Is there nothing special that has to happen when these are reference 
> > > > > parameters?  Can you at least add a test for that?
> > > > Umm, I don't really do references yet (I haven't tested them at all and 
> > > > I don't think they are implemented).
> > > Hmm... that is unfortunate.  We really should be doing references ASAP, 
> > > as they are going to be a pretty critical/oft-needed during testing kinda 
> > > thing.  I'd at least want a commented-out test that you can re-enable 
> > > ASAP.
> > Are not-yet-implemented features consistently implemented such that 
> > constant evaluation will fail with a (possibly unhelpful) diagnostic? As in 
> > https://godbolt.org/z/8vvdca9Ma? If so, can tests be added ahead of time 
> > with annotations for expected errors (essentially false positives to be 
> > addressed later)?
> Some are always (like unhandled AST node), some are not.
An example for this with a reference type is in https://reviews.llvm.org/D132997


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132831

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


[PATCH] D132997: [clang][Interp] Handle DeclRefExpr of reference types

2022-09-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 457193.

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

https://reviews.llvm.org/D132997

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/test/AST/Interp/arrays.cpp
  clang/test/AST/Interp/references.cpp

Index: clang/test/AST/Interp/references.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/references.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+// ref-no-diagnostics
+
+constexpr int a = 10;
+constexpr const int &b = a;
+static_assert(a == b, "");
+
+constexpr int assignToReference() {
+  int a = 20;
+  int &b =a;
+
+  b = 100;
+  return a;
+}
+static_assert(assignToReference() == 100, "");
+
+
+constexpr void setValue(int &dest, int val) {
+  dest = val;
+}
+
+constexpr int checkSetValue() {
+  int l = 100;
+  setValue(l, 200);
+  return l;
+}
+static_assert(checkSetValue() == 200, "");
+
+constexpr int readLocalRef() {
+  int a = 20;
+  int &b = a;
+  return b;
+}
+static_assert(readLocalRef() == 20, "");
+
+constexpr int incRef() {
+  int a = 0;
+  int &b = a;
+
+  b = b + 1;
+
+  return a;
+}
+static_assert(incRef() == 1, "");
+
+
+template
+constexpr void Plus3(int &A) {
+  A = V + 3;
+}
+constexpr int foo = 4;
+
+constexpr int callTemplate() {
+  int a = 3;
+  Plus3(a);
+  return a;
+}
+static_assert(callTemplate() == 7, "");
+
+
+constexpr int& getValue(int *array, int index) {
+  return array[index];
+}
+constexpr int testGetValue() {
+  int values[] = {1, 2, 3, 4};
+  getValue(values, 2) = 30;
+  return values[2];
+}
+static_assert(testGetValue() == 30, "");
+
+// FIXME: ExprWithCleanups + MaterializeTemporaryExpr not implemented
+constexpr const int &MCE = 1; // expected-error{{must be initialized by a constant expression}}
Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -45,6 +45,13 @@
 static_assert(getElementOf(foo[0], 1) == &m, "");
 
 
+template 
+constexpr T& getElementOfArray(T (&array)[N], int I) {
+  return array[I];
+}
+static_assert(getElementOfArray(foo[2], 3) == &m, "");
+
+
 constexpr int data[] = {5, 4, 3, 2, 1};
 static_assert(data[0] == 4, ""); // expected-error{{failed}} \
  // expected-note{{5 == 4}} \
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -845,15 +845,38 @@
 template 
 bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) {
   const auto *Decl = E->getDecl();
+  bool IsReference = Decl->getType()->isReferenceType();
+  bool FoundDecl = false;
 
   if (auto It = Locals.find(Decl); It != Locals.end()) {
 const unsigned Offset = It->second.Offset;
-return this->emitGetPtrLocal(Offset, E);
+if (!this->emitGetPtrLocal(Offset, E))
+  return false;
+
+FoundDecl = true;
   } else if (auto GlobalIndex = P.getGlobal(Decl)) {
-return this->emitGetPtrGlobal(*GlobalIndex, E);
+if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+  return false;
+
+FoundDecl = true;
   } else if (const auto *PVD = dyn_cast(Decl)) {
-if (auto It = this->Params.find(PVD); It != this->Params.end())
-  return this->emitGetPtrParam(It->second, E);
+if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+  if (!this->emitGetPtrParam(It->second, E))
+return false;
+
+  FoundDecl = true;
+}
+  }
+
+  // References are implemented using pointers, so when we get here,
+  // we have a pointer to a pointer, which we need to de-reference once.
+  if (FoundDecl) {
+if (IsReference) {
+  if (!this->emitLoadPop(PT_Ptr, E))
+return false;
+}
+
+return true;
   }
 
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132997: [clang][Interp] Handle DeclRefExpr of reference types

2022-09-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

In D132997#3763094 , @shafik wrote:

> I think like @aaron.ballman was saying in another PR you should aim for as 
> complete set of tests as possible even if you have to comment one that can't 
> work yet. For example cases that would involve `MemberExpr` or `UsingShadow` 
> for example as well as the cases you mentioned not implemented in your 
> description.

I get it for the `MaterializeTemporaryExpr`s, but I don't understand why I 
would add tests using `MemberExpr` now and not when I work on record types (and 
references have already landed).


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

https://reviews.llvm.org/D132997

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


[PATCH] D132136: [clang] Perform implicit lvalue-to-rvalue cast with new interpreter

2022-09-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

@aaron.ballman Can you comment on my last question? I'd like to land this patch 
since the others depend on it.


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

https://reviews.llvm.org/D132136

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


[PATCH] D132997: [clang][Interp] Handle DeclRefExpr of reference types

2022-09-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 457498.

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

https://reviews.llvm.org/D132997

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/test/AST/Interp/arrays.cpp
  clang/test/AST/Interp/references.cpp

Index: clang/test/AST/Interp/references.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/references.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+// ref-no-diagnostics
+
+constexpr int a = 10;
+constexpr const int &b = a;
+static_assert(a == b, "");
+
+constexpr int assignToReference() {
+  int a = 20;
+  int &b =a;
+
+  b = 100;
+  return a;
+}
+static_assert(assignToReference() == 100, "");
+
+
+constexpr void setValue(int &dest, int val) {
+  dest = val;
+}
+
+constexpr int checkSetValue() {
+  int l = 100;
+  setValue(l, 200);
+  return l;
+}
+static_assert(checkSetValue() == 200, "");
+
+constexpr int readLocalRef() {
+  int a = 20;
+  int &b = a;
+  return b;
+}
+static_assert(readLocalRef() == 20, "");
+
+constexpr int incRef() {
+  int a = 0;
+  int &b = a;
+
+  b = b + 1;
+
+  return a;
+}
+static_assert(incRef() == 1, "");
+
+
+template
+constexpr void Plus3(int &A) {
+  A = V + 3;
+}
+constexpr int foo = 4;
+
+constexpr int callTemplate() {
+  int a = 3;
+  Plus3(a);
+  return a;
+}
+static_assert(callTemplate() == 7, "");
+
+
+constexpr int& getValue(int *array, int index) {
+  return array[index];
+}
+constexpr int testGetValue() {
+  int values[] = {1, 2, 3, 4};
+  getValue(values, 2) = 30;
+  return values[2];
+}
+static_assert(testGetValue() == 30, "");
+
+// FIXME: ExprWithCleanups + MaterializeTemporaryExpr not implemented
+constexpr const int &MCE = 1; // expected-error{{must be initialized by a constant expression}}
Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -45,6 +45,13 @@
 static_assert(getElementOf(foo[0], 1) == &m, "");
 
 
+template 
+constexpr T& getElementOfArray(T (&array)[N], int I) {
+  return array[I];
+}
+static_assert(getElementOfArray(foo[2], 3) == &m, "");
+
+
 constexpr int data[] = {5, 4, 3, 2, 1};
 static_assert(data[0] == 4, ""); // expected-error{{failed}} \
  // expected-note{{5 == 4}} \
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -845,15 +845,38 @@
 template 
 bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) {
   const auto *Decl = E->getDecl();
+  bool IsReference = Decl->getType()->isReferenceType();
+  bool FoundDecl = false;
 
   if (auto It = Locals.find(Decl); It != Locals.end()) {
 const unsigned Offset = It->second.Offset;
-return this->emitGetPtrLocal(Offset, E);
+if (!this->emitGetPtrLocal(Offset, E))
+  return false;
+
+FoundDecl = true;
   } else if (auto GlobalIndex = P.getGlobal(Decl)) {
-return this->emitGetPtrGlobal(*GlobalIndex, E);
+if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+  return false;
+
+FoundDecl = true;
   } else if (const auto *PVD = dyn_cast(Decl)) {
-if (auto It = this->Params.find(PVD); It != this->Params.end())
-  return this->emitGetPtrParam(It->second, E);
+if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+  if (!this->emitGetPtrParam(It->second, E))
+return false;
+
+  FoundDecl = true;
+}
+  }
+
+  // References are implemented using pointers, so when we get here,
+  // we have a pointer to a pointer, which we need to de-reference once.
+  if (FoundDecl) {
+if (IsReference) {
+  if (!this->emitLoadPopPtr(E))
+return false;
+}
+
+return true;
   }
 
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132831: [clang][Interp] Handle SubstNonTypeTemplateParmExprs

2022-09-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 457766.
tbaeder marked 2 inline comments as done.

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

https://reviews.llvm.org/D132831

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/test/AST/Interp/functions.cpp


Index: clang/test/AST/Interp/functions.cpp
===
--- clang/test/AST/Interp/functions.cpp
+++ clang/test/AST/Interp/functions.cpp
@@ -65,3 +65,11 @@
   return recursion(i);
 }
 static_assert(recursion(10) == 0, "");
+
+template
+constexpr decltype(N) getNum() {
+  return N;
+}
+static_assert(getNum<-2>() == -2, "");
+static_assert(getNum<10>() == 10, "");
+static_assert(getNum() == 5, "");
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -76,6 +76,7 @@
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
+  bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr 
*E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -231,6 +231,12 @@
   return false;
 }
 
+template 
+bool ByteCodeExprGen::VisitSubstNonTypeTemplateParmExpr(
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);


Index: clang/test/AST/Interp/functions.cpp
===
--- clang/test/AST/Interp/functions.cpp
+++ clang/test/AST/Interp/functions.cpp
@@ -65,3 +65,11 @@
   return recursion(i);
 }
 static_assert(recursion(10) == 0, "");
+
+template
+constexpr decltype(N) getNum() {
+  return N;
+}
+static_assert(getNum<-2>() == -2, "");
+static_assert(getNum<10>() == 10, "");
+static_assert(getNum() == 5, "");
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -76,6 +76,7 @@
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
+  bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -231,6 +231,12 @@
   return false;
 }
 
+template 
+bool ByteCodeExprGen::VisitSubstNonTypeTemplateParmExpr(
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132727: [clang][Interp] Implement array initializers and subscript expressions

2022-09-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 457767.
tbaeder marked 6 inline comments as done.

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

https://reviews.llvm.org/D132727

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/Pointer.cpp
  clang/lib/AST/Interp/Program.cpp
  clang/test/AST/Interp/arrays.cpp

Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -1,13 +1,85 @@
 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
 // RUN: %clang_cc1 -verify=ref %s
 
+constexpr int m = 3;
+constexpr const int *foo[][5] = {
+  {nullptr, &m, nullptr, nullptr, nullptr},
+  {nullptr, nullptr, &m, nullptr, nullptr},
+  {nullptr, nullptr, nullptr, &m, nullptr},
+};
+
+static_assert(foo[0][0] == nullptr, "");
+static_assert(foo[0][1] == &m, "");
+static_assert(foo[0][2] == nullptr, "");
+static_assert(foo[0][3] == nullptr, "");
+static_assert(foo[0][4] == nullptr, "");
+static_assert(foo[1][0] == nullptr, "");
+static_assert(foo[1][1] == nullptr, "");
+static_assert(foo[1][2] == &m, "");
+static_assert(foo[1][3] == nullptr, "");
+static_assert(foo[1][4] == nullptr, "");
+static_assert(foo[2][0] == nullptr, "");
+static_assert(foo[2][1] == nullptr, "");
+static_assert(foo[2][2] == nullptr, "");
+static_assert(foo[2][3] == &m, "");
+static_assert(foo[2][4] == nullptr, "");
+
+
+/// A init list for a primitive value.
+constexpr int f{5};
+static_assert(f == 5, "");
+
+
+constexpr int getElement(int i) {
+  int values[] = {1, 4, 9, 16, 25, 36};
+  return values[i];
+}
+static_assert(getElement(1) == 4, "");
+static_assert(getElement(5) == 36, "");
+
+
+template
+constexpr T getElementOf(T* array, int i) {
+  return array[i];
+}
+static_assert(getElementOf(foo[0], 1) == &m, "");
+
 
-/// expected-no-diagnostics
-/// ref-no-diagnostics
+constexpr int data[] = {5, 4, 3, 2, 1};
+static_assert(data[0] == 4, ""); // expected-error{{failed}} \
+ // expected-note{{5 == 4}} \
+ // ref-error{{failed}} \
+ // ref-note{{5 == 4}}
+
+
+constexpr int dynamic[] = {
+  f, 3, 2 + 5, data[3], *getElementOf(foo[2], 3)
+};
+static_assert(dynamic[0] == f, "");
+static_assert(dynamic[3] == 2, "");
+
+
+constexpr int dependent[4] = {
+  0, 1, dependent[0], dependent[1]
+};
+static_assert(dependent[2] == dependent[0], "");
+static_assert(dependent[3] == dependent[1], "");
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wc99-extensions"
 #pragma clang diagnostic ignored "-Winitializer-overrides"
+constexpr int DI[] = {
+  [0] = 10,
+  [1] = 20,
+  30,
+  40,
+  [1] = 50
+};
+static_assert(DI[0] == 10, "");
+static_assert(DI[1] == 50, "");
+static_assert(DI[2] == 30, "");
+static_assert(DI[3] == 40, "");
+
 /// FIXME: The example below tests ImplicitValueInitExprs, but we can't
 ///   currently evaluate other parts of it.
 #if 0
Index: clang/lib/AST/Interp/Program.cpp
===
--- clang/lib/AST/Interp/Program.cpp
+++ clang/lib/AST/Interp/Program.cpp
@@ -334,14 +334,15 @@
   } else {
 // Arrays of composites. In this case, the array is a list of pointers,
 // followed by the actual elements.
-Descriptor *Desc =
+Descriptor *ElemDesc =
 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
-if (!Desc)
+if (!ElemDesc)
   return nullptr;
-InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
+InterpSize ElemSize =
+ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
 if (std::numeric_limits::max() / ElemSize <= NumElems)
   return {};
-return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
+return allocateDescriptor(D, ElemDesc, NumElems, IsConst, IsTemporary,
   IsMutable);
   }
 }
Index: clang/lib/AST/Interp/Pointer.cpp
===
--- clang/lib/AST/Interp/Pointer.cpp
+++ clang/lib/AST/Interp/Pointer.cpp
@@ -106,7 +106,7 @@
 
   // Build the path into the object.
   Pointer Ptr = *this;
-  while (Ptr.isField()) {
+  while (Ptr.isField() || Ptr.isArrayElement()) {
 if (Ptr.isArrayElement()) {
   Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
   Ptr = Ptr.getArray();
@@ -154,7 +154,8 @@
 void Pointer::initialize() const {
   assert(Pointee && "Cannot initialize null pointer");
   Descriptor *Desc = getFieldDesc();
-  if (Desc->isPrimitiveArray()) {
+
+  if (Desc->isArray()) {
 if (!Pointee->IsStatic) {
   // Primitive array initializer.
   InitMa

[PATCH] D132829: [clang][Interp] Handle ImplictValueInitExprs

2022-09-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder marked an inline comment as done.
tbaeder added inline comments.



Comment at: clang/test/AST/Interp/arrays.cpp:13
+///   currently evaluate other parts of it.
+#if 0
+struct fred {

aaron.ballman wrote:
> I wish we could find some solution that didn't require this so that the test 
> case breaks when we do get around to implementing support for the other bits. 
> But this is at least a good start!
Usually we could just keep it enabled and add the appropriate `expected-error` 
parts, but in this case we run into an assertion later on and that doesn't work.


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

https://reviews.llvm.org/D132829

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


[PATCH] D132136: [clang] Perform implicit lvalue-to-rvalue cast with new interpreter

2022-09-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

In D132136#3766958 , @aaron.ballman 
wrote:

> On the one hand, I'm not comfortable landing this without adequate testing, 
> especially because you want to build more stuff on top of it. I think we need 
> to make sure the foundational bits of evaluation are rock solid before 
> building things on top of them. However, on the other hand, this is 
> foundational enough that it's hard to test this bit without other parts of 
> the interpreter being ready. So my preference is to try to add test coverage 
> even if it's failing currently because other parts of the interpreter aren't 
> ready yet. e.g., (imaginary test case, feel free to use better ones)
>
>   template 
>   struct is_same { static constexpr bool value = false; };
>   
>   template 
>   struct is_same { static constexpr bool value = true; };
>   
>   const volatile int i = 0;
>   // Test that lvalue to rvalue conversion ends up stripping top-level 
> qualifiers.
>   // FIXME: this isn't correct yet because we don't have support for 
> qualifier conversions yet.
>   static_assert(is_same::value, "oh no!"); // 
> expected-error {{static assertion failed: oh no!}}
>
> This way, we can start getting extensive test cases written while thinking 
> about the situations specific to lvalue to rvalue conversion (or whatever 
> else is being implemented at the moment) instead of trying to come back and 
> remember to write them later.
>
> Is that reasonable, or is the interpreter in such a state where even this 
> kind of testing is basically impossible to come up with?

Soo... I was gonna tell you that the test case is obviously not going to work 
right now, since record types aren't implemented at all.  //But// the test case 
actually works just fine. However, it also works without the lvalue-to-rvalue 
conversion in `EvaluteAsRValue`. Both with the old and the new interpreter.

I'm going to add an actual unit test that fails without the conversion. But it 
only checks a very simple case, i.e. that a `DeclRefExpr` is returned as an 
integer and not the lvalue.


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

https://reviews.llvm.org/D132136

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


[PATCH] D132136: [clang] Perform implicit lvalue-to-rvalue cast with new interpreter

2022-09-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 457838.
tbaeder added a comment.

Add a unit test.


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

https://reviews.llvm.org/D132136

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/AST/Interp/literals.cpp
  clang/unittests/AST/EvaluateAsRValueTest.cpp

Index: clang/unittests/AST/EvaluateAsRValueTest.cpp
===
--- clang/unittests/AST/EvaluateAsRValueTest.cpp
+++ clang/unittests/AST/EvaluateAsRValueTest.cpp
@@ -107,3 +107,50 @@
 Args));
   }
 }
+
+class CheckLValueToRValueConversionVisitor
+: public clang::RecursiveASTVisitor {
+public:
+  bool VisitDeclRefExpr(const clang::DeclRefExpr *E) {
+clang::Expr::EvalResult Result;
+E->EvaluateAsRValue(Result, E->getDecl()->getASTContext(), true);
+
+EXPECT_TRUE(Result.Val.hasValue());
+// Since EvaluateAsRValue does an implicit lvalue-to-rvalue conversion,
+// the result cannot be a LValue.
+EXPECT_FALSE(Result.Val.isLValue());
+
+return true;
+  }
+};
+
+class CheckConversionAction : public clang::ASTFrontendAction {
+public:
+  std::unique_ptr
+  CreateASTConsumer(clang::CompilerInstance &Compiler,
+llvm::StringRef FilePath) override {
+return std::make_unique();
+  }
+
+private:
+  class Consumer : public clang::ASTConsumer {
+  public:
+~Consumer() override {}
+
+void HandleTranslationUnit(clang::ASTContext &Ctx) override {
+  CheckLValueToRValueConversionVisitor Evaluator;
+  Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());
+}
+  };
+};
+
+TEST(EvaluateAsRValue, LValueToRValueConversionWorks) {
+  std::string ModesToTest[] = {"", "-fexperimental-new-constant-interpreter"};
+  for (std::string const &Mode : ModesToTest) {
+std::vector Args(1, Mode);
+ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique(),
+  "constexpr int a = 20;\n"
+  "static_assert(a == 20, \"\");\n",
+  Args));
+  }
+}
Index: clang/test/AST/Interp/literals.cpp
===
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -11,6 +11,7 @@
 static_assert(number == 10, "");
 static_assert(number != 10, ""); // expected-error{{failed}} \
  // ref-error{{failed}} \
+ // expected-note{{evaluates to}} \
  // ref-note{{evaluates to}}
 
 constexpr bool getTrue() { return true; }
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -14934,25 +14934,27 @@
 /// lvalue-to-rvalue cast if it is an lvalue.
 static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
   assert(!E->isValueDependent());
+
+  if (E->getType().isNull())
+return false;
+
+  if (!CheckLiteralType(Info, E))
+return false;
+
   if (Info.EnableNewConstInterp) {
 if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
   return false;
   } else {
-if (E->getType().isNull())
-  return false;
-
-if (!CheckLiteralType(Info, E))
-  return false;
-
 if (!::Evaluate(Result, Info, E))
   return false;
+  }
 
-if (E->isGLValue()) {
-  LValue LV;
-  LV.setFrom(Info.Ctx, Result);
-  if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
-return false;
-}
+  // Implicit lvalue-to-rvalue cast.
+  if (E->isGLValue()) {
+LValue LV;
+LV.setFrom(Info.Ctx, Result);
+if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+  return false;
   }
 
   // Check this core constant expression is a constant expression.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133248: [clang] Fix crash upon stray coloncolon token in C2x mode

2022-09-05 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/include/clang/Parse/Parser.h:863
   bool MightBeCXXScopeToken() {
-return Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
-   (Tok.is(tok::annot_template_id) &&
-NextToken().is(tok::coloncolon)) ||
-   Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super);
+return (getLangOpts().CPlusPlus) &&
+   (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||




Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133248

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


[PATCH] D132136: [clang] Perform implicit lvalue-to-rvalue cast with new interpreter

2022-09-07 Thread Timm Bäder via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG5777c05d1609: [clang] Perform implicit lvalue-to-rvalue cast 
with new interpreter (authored by tbaeder).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132136

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/AST/Interp/literals.cpp
  clang/unittests/AST/EvaluateAsRValueTest.cpp

Index: clang/unittests/AST/EvaluateAsRValueTest.cpp
===
--- clang/unittests/AST/EvaluateAsRValueTest.cpp
+++ clang/unittests/AST/EvaluateAsRValueTest.cpp
@@ -107,3 +107,50 @@
 Args));
   }
 }
+
+class CheckLValueToRValueConversionVisitor
+: public clang::RecursiveASTVisitor {
+public:
+  bool VisitDeclRefExpr(const clang::DeclRefExpr *E) {
+clang::Expr::EvalResult Result;
+E->EvaluateAsRValue(Result, E->getDecl()->getASTContext(), true);
+
+EXPECT_TRUE(Result.Val.hasValue());
+// Since EvaluateAsRValue does an implicit lvalue-to-rvalue conversion,
+// the result cannot be a LValue.
+EXPECT_FALSE(Result.Val.isLValue());
+
+return true;
+  }
+};
+
+class CheckConversionAction : public clang::ASTFrontendAction {
+public:
+  std::unique_ptr
+  CreateASTConsumer(clang::CompilerInstance &Compiler,
+llvm::StringRef FilePath) override {
+return std::make_unique();
+  }
+
+private:
+  class Consumer : public clang::ASTConsumer {
+  public:
+~Consumer() override {}
+
+void HandleTranslationUnit(clang::ASTContext &Ctx) override {
+  CheckLValueToRValueConversionVisitor Evaluator;
+  Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());
+}
+  };
+};
+
+TEST(EvaluateAsRValue, LValueToRValueConversionWorks) {
+  std::string ModesToTest[] = {"", "-fexperimental-new-constant-interpreter"};
+  for (std::string const &Mode : ModesToTest) {
+std::vector Args(1, Mode);
+ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique(),
+  "constexpr int a = 20;\n"
+  "static_assert(a == 20, \"\");\n",
+  Args));
+  }
+}
Index: clang/test/AST/Interp/literals.cpp
===
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -11,6 +11,7 @@
 static_assert(number == 10, "");
 static_assert(number != 10, ""); // expected-error{{failed}} \
  // ref-error{{failed}} \
+ // expected-note{{evaluates to}} \
  // ref-note{{evaluates to}}
 
 constexpr bool getTrue() { return true; }
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -14934,25 +14934,27 @@
 /// lvalue-to-rvalue cast if it is an lvalue.
 static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
   assert(!E->isValueDependent());
+
+  if (E->getType().isNull())
+return false;
+
+  if (!CheckLiteralType(Info, E))
+return false;
+
   if (Info.EnableNewConstInterp) {
 if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
   return false;
   } else {
-if (E->getType().isNull())
-  return false;
-
-if (!CheckLiteralType(Info, E))
-  return false;
-
 if (!::Evaluate(Result, Info, E))
   return false;
+  }
 
-if (E->isGLValue()) {
-  LValue LV;
-  LV.setFrom(Info.Ctx, Result);
-  if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
-return false;
-}
+  // Implicit lvalue-to-rvalue cast.
+  if (E->isGLValue()) {
+LValue LV;
+LV.setFrom(Info.Ctx, Result);
+if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+  return false;
   }
 
   // Check this core constant expression is a constant expression.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132286: [clang][Interp] Implement function calls

2022-09-07 Thread Timm Bäder via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG8e41e6a4eafa: [clang][Interp] Implement function calls 
(authored by tbaeder).

Changed prior to commit:
  https://reviews.llvm.org/D132286?vs=455791&id=458645#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132286

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/EvalEmitter.cpp
  clang/lib/AST/Interp/Function.h
  clang/lib/AST/Interp/Interp.cpp
  clang/lib/AST/Interp/InterpFrame.h
  clang/lib/AST/Interp/Opcodes.td
  clang/test/AST/Interp/cxx20.cpp
  clang/test/AST/Interp/functions.cpp
  clang/utils/TableGen/ClangOpcodesEmitter.cpp

Index: clang/utils/TableGen/ClangOpcodesEmitter.cpp
===
--- clang/utils/TableGen/ClangOpcodesEmitter.cpp
+++ clang/utils/TableGen/ClangOpcodesEmitter.cpp
@@ -120,6 +120,9 @@
 
 OS << "case OP_" << ID << ": {\n";
 
+if (CanReturn)
+  OS << "  bool DoReturn = (S.Current == StartFrame);\n";
+
 // Emit calls to read arguments.
 for (size_t I = 0, N = Args.size(); I < N; ++I) {
   OS << "  auto V" << I;
@@ -146,6 +149,9 @@
 if (CanReturn) {
   OS << "  if (!S.Current || S.Current->isRoot())\n";
   OS << "return true;\n";
+
+  OS << "  if (DoReturn)\n";
+  OS << "return true;\n";
 }
 
 OS << "  continue;\n";
Index: clang/test/AST/Interp/functions.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/functions.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+constexpr void doNothing() {}
+constexpr int gimme5() {
+  doNothing();
+  return 5;
+}
+static_assert(gimme5() == 5, "");
+
+
+template constexpr T identity(T t) { return t; }
+static_assert(identity(true), "");
+static_assert(identity(true), ""); /// Compiled bytecode should be cached
+static_assert(!identity(false), "");
+
+constexpr auto add(int a, int b) -> int {
+  return identity(a) + identity(b);
+}
+
+constexpr int sub(int a, int b) {
+  return a - b;
+}
+static_assert(sub(5, 2) == 3, "");
+static_assert(sub(0, 5) == -5, "");
+
+constexpr int norm(int n) {
+  if (n >= 0) {
+return identity(n);
+  }
+  return -identity(n);
+}
+static_assert(norm(5) == norm(-5), "");
+
+constexpr int square(int n) {
+  return norm(n) * norm(n);
+}
+static_assert(square(2) == 4, "");
+
+constexpr int add_second(int a, int b, bool doAdd = true) {
+  if (doAdd)
+return a + b;
+  return a;
+}
+static_assert(add_second(10, 3, true) == 13, "");
+static_assert(add_second(10, 3) == 13, "");
+static_assert(add_second(300, -20, false) == 300, "");
+
+
+constexpr int sub(int a, int b, int c) {
+  return a - b - c;
+}
+static_assert(sub(10, 8, 2) == 0, "");
+
+
+constexpr int recursion(int i) {
+  doNothing();
+  i = i - 1;
+  if (i == 0)
+return identity(0);
+
+  return recursion(i);
+}
+static_assert(recursion(10) == 0, "");
Index: clang/test/AST/Interp/cxx20.cpp
===
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -10,7 +10,7 @@
   int *p = &a;
   return *p;
 }
-//static_assert(getMinus5() == -5, "") TODO
+static_assert(getMinus5() == -5, "");
 
 constexpr int assign() {
   int m = 10;
@@ -20,7 +20,7 @@
 
   return m;
 }
-//static_assert(assign() == 20, "");  TODO
+static_assert(assign() == 20, "");
 
 
 constexpr int pointerAssign() {
@@ -31,7 +31,7 @@
 
   return m;
 }
-//static_assert(pointerAssign() == 12, "");  TODO
+static_assert(pointerAssign() == 12, "");
 
 constexpr int pointerDeref() {
   int m = 12;
@@ -39,7 +39,7 @@
 
   return *p;
 }
-//static_assert(pointerDeref() == 12, ""); TODO
+static_assert(pointerDeref() == 12, "");
 
 constexpr int pointerAssign2() {
   int m = 10;
@@ -52,4 +52,4 @@
 
   return v;
 }
-//static_assert(pointerAssign2() == 12, ""); TODO
+static_assert(pointerAssign2() == 12, "");
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -42,7 +42,7 @@
 def ArgUint64 : ArgType { let Name = "uint64_t"; }
 def ArgBool : ArgType { let Name = "bool"; }
 
-def ArgFunction : ArgType { let Name = "Function *"; }
+def ArgFunction : ArgType { let Name = "const Function *"; }
 def ArgRecord : ArgType { let Name = "Record *"; }
 
 def ArgSema : ArgType { let Name = "const fltSemantics *"; }
@@ -153,6 +153,22 @@
 // [] -> EXIT
 def NoRet : Opcode {}
 
+
+def Call : Opcode {
+  let Args = [ArgFunction];
+  let Types = [AllTypeClass];
+  let ChangesPC = 1;
+  let HasCustomEval = 1;
+  let HasGroup = 1;
+}
+
+def CallVoid : Opcode {
+  let Args = [ArgFunc

[PATCH] D132739: [clang][Interp] Implement IntegralToBoolean casts

2022-09-07 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
tbaeder marked an inline comment as done.
Closed by commit rG95e6a407d92b: [clang][Interp] Implement IntegralToBoolean 
casts (authored by tbaeder).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132739

Files:
  clang/lib/AST/Interp/Boolean.h
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/Opcodes.td
  clang/test/AST/Interp/literals.cpp

Index: clang/test/AST/Interp/literals.cpp
===
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -14,6 +14,37 @@
  // expected-note{{evaluates to}} \
  // ref-note{{evaluates to}}
 
+constexpr bool b = number;
+static_assert(b, "");
+constexpr int one = true;
+static_assert(one == 1, "");
+
+namespace IntegralCasts {
+  constexpr int i = 12;
+  constexpr unsigned int ui = i;
+  static_assert(ui == 12, "");
+  constexpr unsigned int ub = !false;
+  static_assert(ub == 1, "");
+
+  constexpr int si = ui;
+  static_assert(si == 12, "");
+  constexpr int sb = true;
+  static_assert(sb == 1, "");
+
+  constexpr int zero = 0;
+  constexpr unsigned int uzero = 0;
+  constexpr bool bs = i;
+  static_assert(bs, "");
+  constexpr bool bu = ui;
+  static_assert(bu, "");
+  constexpr bool ns = zero;
+  static_assert(!ns, "");
+  constexpr bool nu = uzero;
+  static_assert(!nu, "");
+};
+
+
+
 constexpr bool getTrue() { return true; }
 constexpr bool getFalse() { return false; }
 constexpr void* getNull() { return nullptr; }
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -425,12 +425,16 @@
 //===--===//
 // TODO: Expand this to handle casts between more types.
 
-def Sint32TypeClass : TypeClass {
-  let Types = [Sint32];
+def FromCastTypeClass : TypeClass {
+  let Types = [Uint32, Sint32, Bool];
+}
+
+def ToCastTypeClass : TypeClass {
+  let Types = [Uint32, Sint32, Bool];
 }
 
 def Cast: Opcode {
-  let Types = [BoolTypeClass, Sint32TypeClass];
+  let Types = [FromCastTypeClass, ToCastTypeClass];
   let HasGroup = 1;
 }
 
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -117,6 +117,7 @@
   case CK_NullToPointer:
 return this->Visit(SubExpr);
 
+  case CK_IntegralToBoolean:
   case CK_IntegralCast: {
 Optional FromT = classify(SubExpr->getType());
 Optional ToT = classify(CE->getType());
@@ -132,19 +133,6 @@
   case CK_ToVoid:
 return discard(SubExpr);
 
-  case CK_IntegralToBoolean:
-// Compare integral from Subexpr with 0
-if (Optional T = classify(SubExpr->getType())) {
-  if (!this->Visit(SubExpr))
-return false;
-
-  if (!this->emitConst(SubExpr, 0))
-return false;
-
-  return this->emitNE(*T, SubExpr);
-}
-return false;
-
   default:
 assert(false && "Cast not implemented");
   }
Index: clang/lib/AST/Interp/Boolean.h
===
--- clang/lib/AST/Interp/Boolean.h
+++ clang/lib/AST/Interp/Boolean.h
@@ -50,6 +50,7 @@
   explicit operator int64_t() const { return V; }
   explicit operator uint64_t() const { return V; }
   explicit operator int() const { return V; }
+  explicit operator bool() const { return V; }
 
   APSInt toAPSInt() const {
 return APSInt(APInt(1, static_cast(V), false), true);
@@ -85,9 +86,10 @@
   static Boolean min(unsigned NumBits) { return Boolean(false); }
   static Boolean max(unsigned NumBits) { return Boolean(true); }
 
-  template 
-  static std::enable_if_t::value, Boolean> from(T Value) {
-return Boolean(Value != 0);
+  template  static Boolean from(T Value) {
+if constexpr (std::is_integral::value)
+  return Boolean(Value != 0);
+return Boolean(static_cast(Value) != 0);
   }
 
   template 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132829: [clang][Interp] Handle ImplictValueInitExprs

2022-09-07 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
tbaeder marked an inline comment as done.
Closed by commit rG4d700ffe67be: [clang][Interp] Implement 
ImplicitValueInitExprs (authored by tbaeder).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132829

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Opcodes.td
  clang/test/AST/Interp/arrays.cpp


Index: clang/test/AST/Interp/arrays.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/arrays.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+/// expected-no-diagnostics
+/// ref-no-diagnostics
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#pragma clang diagnostic ignored "-Winitializer-overrides"
+/// FIXME: The example below tests ImplicitValueInitExprs, but we can't
+///   currently evaluate other parts of it.
+#if 0
+struct fred {
+  char s [6];
+  int n;
+};
+
+struct fred y [] = { [0] = { .s[0] = 'q' } };
+#endif
+#pragma clang diagnostic pop
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -203,6 +203,7 @@
 // [] -> [Integer]
 def Zero : Opcode {
   let Types = [AluTypeClass];
+  let HasGroup = 1;
 }
 
 // [] -> [Pointer]
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -75,6 +75,7 @@
   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
+  bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -223,6 +223,14 @@
   return this->bail(BO);
 }
 
+template 
+bool ByteCodeExprGen::VisitImplicitValueInitExpr(const 
ImplicitValueInitExpr *E) {
+  if (Optional T = classify(E))
+return this->emitZero(*T, E);
+
+  return false;
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);


Index: clang/test/AST/Interp/arrays.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/arrays.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+/// expected-no-diagnostics
+/// ref-no-diagnostics
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#pragma clang diagnostic ignored "-Winitializer-overrides"
+/// FIXME: The example below tests ImplicitValueInitExprs, but we can't
+///   currently evaluate other parts of it.
+#if 0
+struct fred {
+  char s [6];
+  int n;
+};
+
+struct fred y [] = { [0] = { .s[0] = 'q' } };
+#endif
+#pragma clang diagnostic pop
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -203,6 +203,7 @@
 // [] -> [Integer]
 def Zero : Opcode {
   let Types = [AluTypeClass];
+  let HasGroup = 1;
 }
 
 // [] -> [Pointer]
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -75,6 +75,7 @@
   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
+  bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -223,6 +223,14 @@
   return this->bail(BO);
 }
 
+template 
+bool ByteCodeExprGen::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+  if (Optional T = classify(E))
+return this->emitZero(*T, E);
+
+  return false;
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

[PATCH] D132831: [clang][Interp] Handle SubstNonTypeTemplateParmExprs

2022-09-07 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG5c4dbff0b6c3: [clang][Interp] Handle 
SubstNonTypeTemplateParmExprs (authored by tbaeder).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132831

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/test/AST/Interp/functions.cpp


Index: clang/test/AST/Interp/functions.cpp
===
--- clang/test/AST/Interp/functions.cpp
+++ clang/test/AST/Interp/functions.cpp
@@ -65,3 +65,11 @@
   return recursion(i);
 }
 static_assert(recursion(10) == 0, "");
+
+template
+constexpr decltype(N) getNum() {
+  return N;
+}
+static_assert(getNum<-2>() == -2, "");
+static_assert(getNum<10>() == 10, "");
+static_assert(getNum() == 5, "");
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -76,6 +76,7 @@
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
+  bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr 
*E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -231,6 +231,12 @@
   return false;
 }
 
+template 
+bool ByteCodeExprGen::VisitSubstNonTypeTemplateParmExpr(
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);


Index: clang/test/AST/Interp/functions.cpp
===
--- clang/test/AST/Interp/functions.cpp
+++ clang/test/AST/Interp/functions.cpp
@@ -65,3 +65,11 @@
   return recursion(i);
 }
 static_assert(recursion(10) == 0, "");
+
+template
+constexpr decltype(N) getNum() {
+  return N;
+}
+static_assert(getNum<-2>() == -2, "");
+static_assert(getNum<10>() == 10, "");
+static_assert(getNum() == 5, "");
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -76,6 +76,7 @@
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
+  bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -231,6 +231,12 @@
   return false;
 }
 
+template 
+bool ByteCodeExprGen::VisitSubstNonTypeTemplateParmExpr(
+const SubstNonTypeTemplateParmExpr *E) {
+  return this->visit(E->getReplacement());
+}
+
 template 
 bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132832: [clang][Interp] Handle missing local initializers better

2022-09-07 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGaa7c5c9c4e5e: [clang][Interp] Handle missing local 
initializers better (authored by tbaeder).

Changed prior to commit:
  https://reviews.llvm.org/D132832?vs=456328&id=458649#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132832

Files:
  clang/lib/AST/Interp/ByteCodeEmitter.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Function.h
  clang/test/AST/Interp/cxx20.cpp

Index: clang/test/AST/Interp/cxx20.cpp
===
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -2,8 +2,6 @@
 // RUN: %clang_cc1 -std=c++20 -verify=ref %s
 
 
-// expected-no-diagnostics
-// ref-no-diagnostics
 constexpr int getMinus5() {
   int a = 10;
   a = -5;
@@ -53,3 +51,12 @@
   return v;
 }
 static_assert(pointerAssign2() == 12, "");
+
+
+constexpr int unInitLocal() {
+  int a;
+  return a; // ref-note{{read of uninitialized object}}
+}
+static_assert(unInitLocal() == 0, ""); // expected-error {{not an integral constant expression}} \
+   // ref-error {{not an integral constant expression}} \
+   // ref-note {{in call to 'unInitLocal()'}}
Index: clang/lib/AST/Interp/Function.h
===
--- clang/lib/AST/Interp/Function.h
+++ clang/lib/AST/Interp/Function.h
@@ -112,6 +112,9 @@
   /// Checks if the function is a constructor.
   bool isConstructor() const { return isa(F); }
 
+  /// Checks if the function is fully done compiling.
+  bool isFullyCompiled() const { return IsFullyCompiled; }
+
 private:
   /// Construct a function representing an actual function.
   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
@@ -128,6 +131,8 @@
 IsValid = true;
   }
 
+  void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
+
 private:
   friend class Program;
   friend class ByteCodeEmitter;
@@ -154,6 +159,9 @@
   llvm::DenseMap Params;
   /// Flag to indicate if the function is valid.
   bool IsValid = false;
+  /// Flag to indicate if the function is done being
+  /// compiled to bytecode.
+  bool IsFullyCompiled = false;
 
 public:
   /// Dumps the disassembled bytecode to \c llvm::errs().
Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -241,11 +241,16 @@
 
   // Integers, pointers, primitives.
   if (Optional T = this->classify(DT)) {
+const Expr *Init = VD->getInit();
+
+if (!Init)
+  return false;
+
 auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
-// Compile the initialiser in its own scope.
+// Compile the initializer in its own scope.
 {
   ExprScope Scope(this);
-  if (!this->visit(VD->getInit()))
+  if (!this->visit(Init))
 return false;
 }
 // Set the value.
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -612,6 +612,14 @@
 }
 assert(Func);
 
+// If the function is being compiled right now, this is a recursive call.
+// In that case, the function can't be valid yet, even though it will be
+// later.
+// If the function is already fully compiled but not constexpr, it was
+// found to be faulty earlier on, so bail out.
+if (Func->isFullyCompiled() && !Func->isConstexpr())
+  return false;
+
 QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
 Optional T = classify(ReturnType);
 
Index: clang/lib/AST/Interp/ByteCodeEmitter.cpp
===
--- clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -62,8 +62,10 @@
 // Return a dummy function if compilation failed.
 if (BailLocation)
   return llvm::make_error(*BailLocation);
-else
+else {
+  Func->setIsFullyCompiled(true);
   return Func;
+}
   } else {
 // Create scopes from descriptors.
 llvm::SmallVector Scopes;
@@ -74,6 +76,7 @@
 // Set the function's code.
 Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
   std::move(Scopes));
+Func->setIsFullyCompiled(true);
 return Func;
   }
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132727: [clang][Interp] Implement array initializers and subscript expressions

2022-09-07 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG3a7d476087df: [clang][Interp] Implement array initializers 
and subscript expressions (authored by tbaeder).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132727

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/Pointer.cpp
  clang/lib/AST/Interp/Program.cpp
  clang/test/AST/Interp/arrays.cpp

Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -1,13 +1,85 @@
 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
 // RUN: %clang_cc1 -verify=ref %s
 
+constexpr int m = 3;
+constexpr const int *foo[][5] = {
+  {nullptr, &m, nullptr, nullptr, nullptr},
+  {nullptr, nullptr, &m, nullptr, nullptr},
+  {nullptr, nullptr, nullptr, &m, nullptr},
+};
+
+static_assert(foo[0][0] == nullptr, "");
+static_assert(foo[0][1] == &m, "");
+static_assert(foo[0][2] == nullptr, "");
+static_assert(foo[0][3] == nullptr, "");
+static_assert(foo[0][4] == nullptr, "");
+static_assert(foo[1][0] == nullptr, "");
+static_assert(foo[1][1] == nullptr, "");
+static_assert(foo[1][2] == &m, "");
+static_assert(foo[1][3] == nullptr, "");
+static_assert(foo[1][4] == nullptr, "");
+static_assert(foo[2][0] == nullptr, "");
+static_assert(foo[2][1] == nullptr, "");
+static_assert(foo[2][2] == nullptr, "");
+static_assert(foo[2][3] == &m, "");
+static_assert(foo[2][4] == nullptr, "");
+
+
+/// A init list for a primitive value.
+constexpr int f{5};
+static_assert(f == 5, "");
+
+
+constexpr int getElement(int i) {
+  int values[] = {1, 4, 9, 16, 25, 36};
+  return values[i];
+}
+static_assert(getElement(1) == 4, "");
+static_assert(getElement(5) == 36, "");
+
+
+template
+constexpr T getElementOf(T* array, int i) {
+  return array[i];
+}
+static_assert(getElementOf(foo[0], 1) == &m, "");
+
 
-/// expected-no-diagnostics
-/// ref-no-diagnostics
+constexpr int data[] = {5, 4, 3, 2, 1};
+static_assert(data[0] == 4, ""); // expected-error{{failed}} \
+ // expected-note{{5 == 4}} \
+ // ref-error{{failed}} \
+ // ref-note{{5 == 4}}
+
+
+constexpr int dynamic[] = {
+  f, 3, 2 + 5, data[3], *getElementOf(foo[2], 3)
+};
+static_assert(dynamic[0] == f, "");
+static_assert(dynamic[3] == 2, "");
+
+
+constexpr int dependent[4] = {
+  0, 1, dependent[0], dependent[1]
+};
+static_assert(dependent[2] == dependent[0], "");
+static_assert(dependent[3] == dependent[1], "");
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wc99-extensions"
 #pragma clang diagnostic ignored "-Winitializer-overrides"
+constexpr int DI[] = {
+  [0] = 10,
+  [1] = 20,
+  30,
+  40,
+  [1] = 50
+};
+static_assert(DI[0] == 10, "");
+static_assert(DI[1] == 50, "");
+static_assert(DI[2] == 30, "");
+static_assert(DI[3] == 40, "");
+
 /// FIXME: The example below tests ImplicitValueInitExprs, but we can't
 ///   currently evaluate other parts of it.
 #if 0
Index: clang/lib/AST/Interp/Program.cpp
===
--- clang/lib/AST/Interp/Program.cpp
+++ clang/lib/AST/Interp/Program.cpp
@@ -334,14 +334,15 @@
   } else {
 // Arrays of composites. In this case, the array is a list of pointers,
 // followed by the actual elements.
-Descriptor *Desc =
+Descriptor *ElemDesc =
 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
-if (!Desc)
+if (!ElemDesc)
   return nullptr;
-InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
+InterpSize ElemSize =
+ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
 if (std::numeric_limits::max() / ElemSize <= NumElems)
   return {};
-return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
+return allocateDescriptor(D, ElemDesc, NumElems, IsConst, IsTemporary,
   IsMutable);
   }
 }
Index: clang/lib/AST/Interp/Pointer.cpp
===
--- clang/lib/AST/Interp/Pointer.cpp
+++ clang/lib/AST/Interp/Pointer.cpp
@@ -106,7 +106,7 @@
 
   // Build the path into the object.
   Pointer Ptr = *this;
-  while (Ptr.isField()) {
+  while (Ptr.isField() || Ptr.isArrayElement()) {
 if (Ptr.isArrayElement()) {
   Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
   Ptr = Ptr.getArray();
@@ -154,7 +154,8 @@
 void Pointer::initialize() const {
   assert(Pointee && "Cannot in

[PATCH] D132997: [clang][Interp] Handle DeclRefExpr of reference types

2022-09-07 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 458662.
tbaeder marked an inline comment as done.

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

https://reviews.llvm.org/D132997

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/test/AST/Interp/arrays.cpp
  clang/test/AST/Interp/references.cpp

Index: clang/test/AST/Interp/references.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/references.cpp
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+// ref-no-diagnostics
+
+constexpr int a = 10;
+constexpr const int &b = a;
+static_assert(a == b, "");
+
+constexpr int assignToReference() {
+  int a = 20;
+  int &b = a;
+
+  b = 100;
+  return a;
+}
+static_assert(assignToReference() == 100, "");
+
+
+constexpr void setValue(int &dest, int val) {
+  dest = val;
+}
+
+constexpr int checkSetValue() {
+  int l = 100;
+  setValue(l, 200);
+  return l;
+}
+static_assert(checkSetValue() == 200, "");
+
+constexpr int readLocalRef() {
+  int a = 20;
+  int &b = a;
+  return b;
+}
+static_assert(readLocalRef() == 20, "");
+
+constexpr int incRef() {
+  int a = 0;
+  int &b = a;
+
+  b = b + 1;
+
+  return a;
+}
+static_assert(incRef() == 1, "");
+
+
+template
+constexpr void Plus3(int &A) {
+  A = V + 3;
+}
+constexpr int foo = 4;
+
+constexpr int callTemplate() {
+  int a = 3;
+  Plus3(a);
+  return a;
+}
+static_assert(callTemplate() == 7, "");
+
+
+constexpr int& getValue(int *array, int index) {
+  return array[index];
+}
+constexpr int testGetValue() {
+  int values[] = {1, 2, 3, 4};
+  getValue(values, 2) = 30;
+  return values[2];
+}
+static_assert(testGetValue() == 30, "");
+
+// FIXME: ExprWithCleanups + MaterializeTemporaryExpr not implemented
+constexpr const int &MCE = 1; // expected-error{{must be initialized by a constant expression}}
+
+
+struct S {
+  int i, j;
+};
+
+constexpr int RefToMemberExpr() {
+  S s{1, 2};
+
+  int &j = s.i;
+  j += 10;
+
+  return j;
+}
+
+static_assert(RefToMemberExpr() == 11, ""); // expected-error{{not an integral constant expression}}
Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -45,6 +45,13 @@
 static_assert(getElementOf(foo[0], 1) == &m, "");
 
 
+template 
+constexpr T& getElementOfArray(T (&array)[N], int I) {
+  return array[I];
+}
+static_assert(getElementOfArray(foo[2], 3) == &m, "");
+
+
 constexpr int data[] = {5, 4, 3, 2, 1};
 static_assert(data[0] == 4, ""); // expected-error{{failed}} \
  // expected-note{{5 == 4}} \
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -845,15 +845,38 @@
 template 
 bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) {
   const auto *Decl = E->getDecl();
+  bool IsReference = Decl->getType()->isReferenceType();
+  bool FoundDecl = false;
 
   if (auto It = Locals.find(Decl); It != Locals.end()) {
 const unsigned Offset = It->second.Offset;
-return this->emitGetPtrLocal(Offset, E);
+if (!this->emitGetPtrLocal(Offset, E))
+  return false;
+
+FoundDecl = true;
   } else if (auto GlobalIndex = P.getGlobal(Decl)) {
-return this->emitGetPtrGlobal(*GlobalIndex, E);
+if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+  return false;
+
+FoundDecl = true;
   } else if (const auto *PVD = dyn_cast(Decl)) {
-if (auto It = this->Params.find(PVD); It != this->Params.end())
-  return this->emitGetPtrParam(It->second, E);
+if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+  if (!this->emitGetPtrParam(It->second, E))
+return false;
+
+  FoundDecl = true;
+}
+  }
+
+  // References are implemented using pointers, so when we get here,
+  // we have a pointer to a pointer, which we need to de-reference once.
+  if (FoundDecl) {
+if (IsReference) {
+  if (!this->emitLoadPopPtr(E))
+return false;
+}
+
+return true;
   }
 
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132727: [clang][Interp] Implement array initializers and subscript expressions

2022-09-08 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

Thanks @MaskRay, I thought this was fixed by 
https://github.com/llvm/llvm-project/commit/86271798e51a7866dd2af44e0ee183d1331089e6,
 at least all the emails I got about failing msan builds were missing that 
change.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132727

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


[PATCH] D133753: [clang][Interp] WIP: Array fillers

2022-09-13 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: erichkeane, aaron.ballman, shafik, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Uploading this now to get some early feedback on the approach and maybe find 
some better tests.

Pointers in the VM are implemented through the `Pointer` class. Each `Pointer` 
points to a `Block`, which represent memory. However, each `Block` also knows 
all the `Pointer`s pointing at it. I've used this to find simply replace a 
`Block` representing an array with a larger one and update all pointers 
pointing to said block (`Block::transferPointers()`). This is the core of it 
all, but it requires quite a few smaller changes that could be broken out of 
this patch of course. Like enabling pointer tracking for static `Block`s.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133753

Files:
  clang/lib/AST/Interp/Boolean.h
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/Context.cpp
  clang/lib/AST/Interp/Descriptor.cpp
  clang/lib/AST/Interp/Descriptor.h
  clang/lib/AST/Interp/EvalEmitter.cpp
  clang/lib/AST/Interp/Integral.h
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/InterpBlock.cpp
  clang/lib/AST/Interp/InterpBlock.h
  clang/lib/AST/Interp/InterpFrame.cpp
  clang/lib/AST/Interp/InterpFrame.h
  clang/lib/AST/Interp/InterpStack.h
  clang/lib/AST/Interp/Pointer.cpp
  clang/lib/AST/Interp/Pointer.h
  clang/lib/AST/Interp/Program.cpp
  clang/lib/AST/Interp/Program.h
  clang/test/AST/Interp/arrays.cpp

Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -98,3 +98,59 @@
 struct fred y [] = { [0] = { .s[0] = 'q' } };
 #endif
 #pragma clang diagnostic pop
+
+namespace indices {
+  constexpr int first[] = {1};
+  constexpr int firstValue = first[2]; // ref-error {{must be initialized by a constant expression}} \
+   // ref-note {{cannot refer to element 2 of array of 1}} \
+   // expected-error {{must be initialized by a constant expression}} \
+   // expected-note {{cannot refer to element 2 of array of 1}}
+
+  constexpr int second[10] = {17};
+  constexpr int secondValue = second[10];// ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{read of dereferenced one-past-the-end pointer}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{cannot refer to element 10 of array of 10}}
+
+  constexpr int negative = second[-2]; // ref-error {{must be initialized by a constant expression}} \
+   // ref-note {{cannot refer to element -2 of array of 10}} \
+   // expected-error {{must be initialized by a constant expression}} \
+   // expected-note {{cannot refer to element -2 of array of 10}}
+};
+
+namespace fillers {
+  constexpr int k[3] = {1337};
+  constexpr int foo(int m) {
+return k[m];
+  }
+  static_assert(foo(0) == 1337, "");
+  static_assert(foo(1) == 0, "");
+  static_assert(foo(2) == 0, "");
+
+  constexpr int N = 12;
+  constexpr int local(unsigned i) {
+int arr[N] = {1,2,3};
+return arr[i];
+  }
+  static_assert(local(0) == 1, "");
+  static_assert(local(1) == 2, "");
+  static_assert(local(2) == 3, "");
+  static_assert(local(3) == 0, "");
+  static_assert(local(N - 1) == 0, "");
+
+  /// FIXME: Non-primitive array fillers are not handled properly currently,
+  ///   but nobody notices right now because all fillers are 0 anyway and
+  ///   that's also was we memset() the memory to.
+  constexpr int twodim[2][4] = {
+{1,2},
+{3,4}
+  };
+  static_assert(twodim[0][0] == 1, "");
+  static_assert(twodim[0][1] == 2, "");
+  static_assert(twodim[0][2] == 0, "");
+  static_assert(twodim[0][3] == 0, "");
+  static_assert(twodim[1][0] == 3, "");
+  static_assert(twodim[1][1] == 4, "");
+  static_assert(twodim[1][2] == 0, "");
+  static_assert(twodim[1][3] == 0, "");
+};
Index: clang/lib/AST/Interp/Program.h
===
--- clang/lib/AST/Interp/Program.h
+++ clang/lib/AST/Interp/Program.h
@@ -56,7 +56,12 @@
   /// Returns the value of a global.
   Block *getGlobal(unsigned Idx) {
 assert(Idx < Globals.size());
-return Globals[Idx]->block();
+return Globals[Idx].block();
+  }
+
+  /// Checks whether the given pointer points to a global variable.
+  bool isGlobalPointer(const Pointer &P) const {
+return false;
   }
 
   /// Finds a global's index.
@@ -69,7 +74,7 @@
   llvm::Optional getOrCreateDummy(const Par

[PATCH] D132997: [clang][Interp] Handle DeclRefExpr of reference types

2022-09-13 Thread Timm Bäder via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGbf3efa8b1622: [clang][Interp] Handle DeclRefExpr of 
reference types (authored by tbaeder).

Changed prior to commit:
  https://reviews.llvm.org/D132997?vs=458662&id=459681#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132997

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/test/AST/Interp/arrays.cpp
  clang/test/AST/Interp/references.cpp

Index: clang/test/AST/Interp/references.cpp
===
--- /dev/null
+++ clang/test/AST/Interp/references.cpp
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+
+// ref-no-diagnostics
+
+constexpr int a = 10;
+constexpr const int &b = a;
+static_assert(a == b, "");
+
+constexpr int assignToReference() {
+  int a = 20;
+  int &b = a;
+
+  b = 100;
+  return a;
+}
+static_assert(assignToReference() == 100, "");
+
+
+constexpr void setValue(int &dest, int val) {
+  dest = val;
+}
+
+constexpr int checkSetValue() {
+  int l = 100;
+  setValue(l, 200);
+  return l;
+}
+static_assert(checkSetValue() == 200, "");
+
+constexpr int readLocalRef() {
+  int a = 20;
+  int &b = a;
+  return b;
+}
+static_assert(readLocalRef() == 20, "");
+
+constexpr int incRef() {
+  int a = 0;
+  int &b = a;
+
+  b = b + 1;
+
+  return a;
+}
+static_assert(incRef() == 1, "");
+
+
+template
+constexpr void Plus3(int &A) {
+  A = V + 3;
+}
+constexpr int foo = 4;
+
+constexpr int callTemplate() {
+  int a = 3;
+  Plus3(a);
+  return a;
+}
+static_assert(callTemplate() == 7, "");
+
+
+constexpr int& getValue(int *array, int index) {
+  return array[index];
+}
+constexpr int testGetValue() {
+  int values[] = {1, 2, 3, 4};
+  getValue(values, 2) = 30;
+  return values[2];
+}
+static_assert(testGetValue() == 30, "");
+
+// FIXME: ExprWithCleanups + MaterializeTemporaryExpr not implemented
+constexpr const int &MCE = 1; // expected-error{{must be initialized by a constant expression}}
+
+
+struct S {
+  int i, j;
+};
+
+constexpr int RefToMemberExpr() {
+  S s{1, 2};
+
+  int &j = s.i;
+  j += 10;
+
+  return j;
+}
+// FIXME: Should be accepted.
+static_assert(RefToMemberExpr() == 11, ""); // expected-error{{not an integral constant expression}}
Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -45,6 +45,13 @@
 static_assert(getElementOf(foo[0], 1) == &m, "");
 
 
+template 
+constexpr T& getElementOfArray(T (&array)[N], int I) {
+  return array[I];
+}
+static_assert(getElementOfArray(foo[2], 3) == &m, "");
+
+
 constexpr int data[] = {5, 4, 3, 2, 1};
 static_assert(data[0] == 4, ""); // expected-error{{failed}} \
  // expected-note{{5 == 4}} \
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -814,15 +814,38 @@
 template 
 bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) {
   const auto *Decl = E->getDecl();
+  bool IsReference = Decl->getType()->isReferenceType();
+  bool FoundDecl = false;
 
   if (auto It = Locals.find(Decl); It != Locals.end()) {
 const unsigned Offset = It->second.Offset;
-return this->emitGetPtrLocal(Offset, E);
+if (!this->emitGetPtrLocal(Offset, E))
+  return false;
+
+FoundDecl = true;
   } else if (auto GlobalIndex = P.getGlobal(Decl)) {
-return this->emitGetPtrGlobal(*GlobalIndex, E);
+if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+  return false;
+
+FoundDecl = true;
   } else if (const auto *PVD = dyn_cast(Decl)) {
-if (auto It = this->Params.find(PVD); It != this->Params.end())
-  return this->emitGetPtrParam(It->second, E);
+if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+  if (!this->emitGetPtrParam(It->second, E))
+return false;
+
+  FoundDecl = true;
+}
+  }
+
+  // References are implemented using pointers, so when we get here,
+  // we have a pointer to a pointer, which we need to de-reference once.
+  if (FoundDecl) {
+if (IsReference) {
+  if (!this->emitLoadPopPtr(E))
+return false;
+}
+
+return true;
   }
 
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133753: [clang][Interp] WIP: Array fillers

2022-09-14 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/Context.cpp:54
+  assert(Stk.empty());
+  return true;
 }

The additional asserts I inserted here could be in another patch. However, I 
added them because I ran into a peculiar problem: when creating a `Pointer`, it 
calls `Pointee->addPointer(this)`. It will only remove itself from the pointee 
again in its destructor. //But// the destructor is not (necessarily) being 
called at all because the `Pointer` is constructed in the stack (or otherwise 
placement-new'ed into a larger memory region).



Comment at: clang/lib/AST/Interp/Interp.h:832
+_B->invokeCtor();
+
+memcpy(_B->data(), Pointee->data(), Desc->getAllocSize());

Note here that both the block and the descriptor are leaked. They are usually 
allocated in `Program`, which uses its own allocator for them. I'm not 100% 
sure what to do about this, since the blocks have different lifetimes depending 
on if they are for global or local variables (or parameters).
 Short of introducing a `Program::managesBlock(Block* B)` that just does a 
linear search for the blocks.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133753

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


[PATCH] D133856: [clang][Interp] Pass initializer through when creating variables

2022-09-14 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, shafik, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This is of course in preparation of https://reviews.llvm.org/D133753. I think 
this patch is needed no matter how the array filler approach ends up.

Pass the initializer of the variable through when creating variables. This way 
we can later inspect the initializer in `Program::createDescriptor()` for the 
array size.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133856

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/Program.cpp
  clang/lib/AST/Interp/Program.h

Index: clang/lib/AST/Interp/Program.h
===
--- clang/lib/AST/Interp/Program.h
+++ clang/lib/AST/Interp/Program.h
@@ -69,7 +69,7 @@
   llvm::Optional getOrCreateDummy(const ParmVarDecl *PD);
 
   /// Creates a global and returns its index.
-  llvm::Optional createGlobal(const ValueDecl *VD);
+  llvm::Optional createGlobal(const ValueDecl *VD, const Expr *E);
 
   /// Creates a global from a lifetime-extended temporary.
   llvm::Optional createGlobal(const Expr *E);
@@ -111,7 +111,8 @@
   /// Creates a descriptor for a composite type.
   Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
bool IsConst = false, bool IsTemporary = false,
-   bool IsMutable = false);
+   bool IsMutable = false,
+   const Expr *Init = nullptr);
 
   /// Context to manage declaration lifetimes.
   class DeclScope {
@@ -134,7 +135,8 @@
   friend class DeclScope;
 
   llvm::Optional createGlobal(const DeclTy &D, QualType Ty,
-bool IsStatic, bool IsExtern);
+bool IsStatic, bool IsExtern,
+const Expr *Init = nullptr);
 
   /// Reference to the VM context.
   Context &Ctx;
Index: clang/lib/AST/Interp/Program.cpp
===
--- clang/lib/AST/Interp/Program.cpp
+++ clang/lib/AST/Interp/Program.cpp
@@ -127,7 +127,7 @@
   if (auto Idx = getGlobal(VD))
 return Idx;
 
-  if (auto Idx = createGlobal(VD)) {
+  if (auto Idx = createGlobal(VD, nullptr)) {
 GlobalIndices[VD] = *Idx;
 return Idx;
   }
@@ -153,7 +153,8 @@
   return {};
 }
 
-llvm::Optional Program::createGlobal(const ValueDecl *VD) {
+llvm::Optional Program::createGlobal(const ValueDecl *VD,
+   const Expr *Init) {
   bool IsStatic, IsExtern;
   if (auto *Var = dyn_cast(VD)) {
 IsStatic = !Var->hasLocalStorage();
@@ -162,7 +163,7 @@
 IsStatic = false;
 IsExtern = true;
   }
-  if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern)) {
+  if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) {
 for (const Decl *P = VD; P; P = P->getPreviousDecl())
   GlobalIndices[P] = *Idx;
 return *Idx;
@@ -175,7 +176,8 @@
 }
 
 llvm::Optional Program::createGlobal(const DeclTy &D, QualType Ty,
-   bool IsStatic, bool IsExtern) {
+   bool IsStatic, bool IsExtern,
+   const Expr *Init) {
   // Create a descriptor for the global.
   Descriptor *Desc;
   const bool IsConst = Ty.isConstQualified();
@@ -310,7 +312,7 @@
 
 Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
   bool IsConst, bool IsTemporary,
-  bool IsMutable) {
+  bool IsMutable, const Expr *Init) {
   // Classes and structures.
   if (auto *RT = Ty->getAs()) {
 if (auto *Record = getOrCreateRecord(RT->getDecl()))
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -513,18 +513,23 @@
   QualType Ty;
 
   const ValueDecl *Key = nullptr;
+  const Expr *Init = nullptr;
   bool IsTemporary = false;
-  if (auto *VD = dyn_cast_or_null(Src.dyn_cast())) {
+  if (auto *VD = dyn_cast_if_present(Src.dyn_cast())) {
 Key = VD;
 Ty = VD->getType();
+
+if (const auto *VarD = dyn_cast(VD))
+  Init = VarD->getInit();
   }
   if (auto *E = Src.dyn_cast()) {
 IsTemporary = true;
 Ty = E->getType();
   }
 
-  Descriptor *D = P.createDescriptor(Src, Ty.getTypePtr(),
- Ty.isConstQualified(), IsTemporary);
+  Descriptor *D =
+  P.createDescriptor(Src, Ty.getTypePtr(), Ty.isConstQualified(),
+ IsTemporary, /*IsMutable=*/false, Init);
   if (!D)

[PATCH] D133753: [clang][Interp] WIP: Array fillers

2022-09-14 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 460059.

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

https://reviews.llvm.org/D133753

Files:
  clang/lib/AST/Interp/Boolean.h
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/Context.cpp
  clang/lib/AST/Interp/Descriptor.cpp
  clang/lib/AST/Interp/Descriptor.h
  clang/lib/AST/Interp/EvalEmitter.cpp
  clang/lib/AST/Interp/Integral.h
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/InterpBlock.cpp
  clang/lib/AST/Interp/InterpBlock.h
  clang/lib/AST/Interp/InterpFrame.cpp
  clang/lib/AST/Interp/InterpFrame.h
  clang/lib/AST/Interp/InterpStack.h
  clang/lib/AST/Interp/Pointer.cpp
  clang/lib/AST/Interp/Pointer.h
  clang/lib/AST/Interp/Program.cpp
  clang/lib/AST/Interp/Program.h
  clang/test/AST/Interp/arrays.cpp

Index: clang/test/AST/Interp/arrays.cpp
===
--- clang/test/AST/Interp/arrays.cpp
+++ clang/test/AST/Interp/arrays.cpp
@@ -98,3 +98,59 @@
 struct fred y [] = { [0] = { .s[0] = 'q' } };
 #endif
 #pragma clang diagnostic pop
+
+namespace indices {
+  constexpr int first[] = {1};
+  constexpr int firstValue = first[2]; // ref-error {{must be initialized by a constant expression}} \
+   // ref-note {{cannot refer to element 2 of array of 1}} \
+   // expected-error {{must be initialized by a constant expression}} \
+   // expected-note {{cannot refer to element 2 of array of 1}}
+
+  constexpr int second[10] = {17};
+  constexpr int secondValue = second[10];// ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{read of dereferenced one-past-the-end pointer}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{cannot refer to element 10 of array of 10}}
+
+  constexpr int negative = second[-2]; // ref-error {{must be initialized by a constant expression}} \
+   // ref-note {{cannot refer to element -2 of array of 10}} \
+   // expected-error {{must be initialized by a constant expression}} \
+   // expected-note {{cannot refer to element -2 of array of 10}}
+};
+
+namespace fillers {
+  constexpr int k[3] = {1337};
+  constexpr int foo(int m) {
+return k[m];
+  }
+  static_assert(foo(0) == 1337, "");
+  static_assert(foo(1) == 0, "");
+  static_assert(foo(2) == 0, "");
+
+  constexpr int N = 12;
+  constexpr int local(unsigned i) {
+int arr[N] = {1,2,3};
+return arr[i];
+  }
+  static_assert(local(0) == 1, "");
+  static_assert(local(1) == 2, "");
+  static_assert(local(2) == 3, "");
+  static_assert(local(3) == 0, "");
+  static_assert(local(N - 1) == 0, "");
+
+  /// FIXME: Non-primitive array fillers are not handled properly currently,
+  ///   but nobody notices right now because all fillers are 0 anyway and
+  ///   that's also was we memset() the memory to.
+  constexpr int twodim[2][4] = {
+{1,2},
+{3,4}
+  };
+  static_assert(twodim[0][0] == 1, "");
+  static_assert(twodim[0][1] == 2, "");
+  static_assert(twodim[0][2] == 0, "");
+  static_assert(twodim[0][3] == 0, "");
+  static_assert(twodim[1][0] == 3, "");
+  static_assert(twodim[1][1] == 4, "");
+  static_assert(twodim[1][2] == 0, "");
+  static_assert(twodim[1][3] == 0, "");
+};
Index: clang/lib/AST/Interp/Program.h
===
--- clang/lib/AST/Interp/Program.h
+++ clang/lib/AST/Interp/Program.h
@@ -56,7 +56,12 @@
   /// Returns the value of a global.
   Block *getGlobal(unsigned Idx) {
 assert(Idx < Globals.size());
-return Globals[Idx]->block();
+return Globals[Idx].block();
+  }
+
+  /// Checks whether the given pointer points to a global variable.
+  bool isGlobalPointer(const Pointer &P) const {
+return false;
   }
 
   /// Finds a global's index.
@@ -156,35 +161,12 @@
   /// Custom allocator for global storage.
   using PoolAllocTy = llvm::BumpPtrAllocatorImpl;
 
-  /// Descriptor + storage for a global object.
-  ///
-  /// Global objects never go out of scope, thus they do not track pointers.
-  class Global {
-  public:
-/// Create a global descriptor for string literals.
-template 
-Global(Tys... Args) : B(std::forward(Args)...) {}
-
-/// Allocates the global in the pool, reserving storate for data.
-void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
-  return Alloc.Allocate(Meta + Data, alignof(void *));
-}
-
-/// Return a pointer to the data.
-char *data() { return B.data(); }
-/// Return a pointer to the block.
-Block *block() { return &B; }
-
-  private:
-/// Required metadata - does not actually track pointers.
-Block B;
-  };

[PATCH] D133924: add clang_CXXMethod_isDeleted function

2022-09-15 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/tools/libclang/CIndex.cpp:8870
+  const CXXMethodDecl *Method =
+  D ? dyn_cast_or_null(D->getAsFunction()) : nullptr;
+  return (Method && Method->isDeleted()) ? 1 : 0;




Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133924

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


[PATCH] D133934: [clang][Interp] Handle sizeof() expressions

2022-09-15 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, shafik, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Handle sizeof expressions.

I was a bit unsure here about alignment, but the rest is pretty 
self-explanatory I think.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133934

Files:
  clang/lib/AST/Interp/Boolean.h
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Context.cpp
  clang/lib/AST/Interp/Context.h
  clang/lib/AST/Interp/Opcodes.td
  clang/test/AST/Interp/literals.cpp

Index: clang/test/AST/Interp/literals.cpp
===
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -72,10 +72,30 @@
 constexpr const int* getIntPointer() {
   return &m;
 }
-//static_assert(getIntPointer() == &m, ""); TODO
-//static_assert(*getIntPointer() == 10, ""); TODO
+static_assert(getIntPointer() == &m, "");
+static_assert(*getIntPointer() == 10, "");
 
 constexpr int gimme(int k) {
   return k;
 }
-// static_assert(gimme(5) == 5, ""); TODO
+static_assert(gimme(5) == 5, "");
+
+namespace SizeOf {
+  constexpr int soint = sizeof(int);
+  constexpr int souint = sizeof(unsigned int);
+  static_assert(soint == souint, "");
+
+  static_assert(sizeof(&soint) == sizeof(void*), "");
+  static_assert(sizeof(&soint) == sizeof(nullptr), "");
+
+  static_assert(sizeof(long) == sizeof(unsigned long), "");
+  static_assert(sizeof(char) == sizeof(unsigned char), "");
+
+  constexpr int N = 4;
+  constexpr int arr[N] = {1,2,3,4};
+  static_assert(sizeof(arr) == N * sizeof(int), "");
+  static_assert(sizeof(arr) == N * sizeof(arr[0]), "");
+
+  constexpr bool arrB[N] = {true, true, true, true};
+  static_assert(sizeof(arrB) == N * sizeof(bool), "");
+};
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -427,11 +427,11 @@
 // TODO: Expand this to handle casts between more types.
 
 def FromCastTypeClass : TypeClass {
-  let Types = [Uint32, Sint32, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
 }
 
 def ToCastTypeClass : TypeClass {
-  let Types = [Uint32, Sint32, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
 }
 
 def Cast: Opcode {
Index: clang/lib/AST/Interp/Context.h
===
--- clang/lib/AST/Interp/Context.h
+++ clang/lib/AST/Interp/Context.h
@@ -62,6 +62,9 @@
   /// Classifies an expression.
   llvm::Optional classify(QualType T) const;
 
+  /// Calculate size of \T.
+  llvm::Optional sizeofType(QualType T) const;
+
 private:
   /// Runs a function.
   bool Run(State &Parent, Function *Func, APValue &Result);
Index: clang/lib/AST/Interp/Context.cpp
===
--- clang/lib/AST/Interp/Context.cpp
+++ clang/lib/AST/Interp/Context.cpp
@@ -130,6 +130,25 @@
   return {};
 }
 
+llvm::Optional Context::sizeofType(QualType T) const {
+  if (llvm::Optional ArgT = classify(T))
+return primSize(*ArgT);
+
+  if (const auto *AT = T->getAsArrayTypeUnsafe()) {
+if (const auto *CAT = dyn_cast(T)) {
+  size_t NumElems = CAT->getSize().getZExtValue();
+  QualType ElemType = CAT->getElementType();
+
+  if (llvm::Optional ElemSize = sizeofType(ElemType))
+return NumElems * (*ElemSize);
+}
+  }
+
+  // TODO: Handle record types
+
+  return {};
+}
+
 unsigned Context::getCharBit() const {
   return Ctx.getTargetInfo().getCharWidth();
 }
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -80,6 +80,7 @@
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
   bool VisitInitListExpr(const InitListExpr *E);
   bool VisitConstantExpr(const ConstantExpr *E);
+  bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -281,7 +281,20 @@
 }
 
 template 
-bool ByteCodeExprGen::discard(const Expr *E) {
+bool ByteCodeExprGen::VisitUnaryExprOrTypeTraitExpr(
+const UnaryExprOrTypeTraitExpr *E) {
+
+  if (E->getKind() == UETT_SizeOf) {
+QualType ArgType = E->getTypeOfArgument();
+
+if (Optional ArgSize = Ctx.sizeofType(ArgType))
+  return this->emitConst(E, *ArgSize);
+  }
+
+  return false;
+}
+
+template  bool ByteCodeExprGen::discard(const Expr *E) 

[PATCH] D133941: [clang][Interp] Record item types in InterpStack

2022-09-15 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, shafik, erichkeane, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Since I've run into this a few times now...

When `push()`ing something on the stack, we need to later `pop()` the correct 
type of value, otherwise we run into problems.

This s just an idea and I've disabled it if `NDEBUG` is defined. The current 
tests all still work though, which is good.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133941

Files:
  clang/lib/AST/Interp/InterpStack.h


Index: clang/lib/AST/Interp/InterpStack.h
===
--- clang/lib/AST/Interp/InterpStack.h
+++ clang/lib/AST/Interp/InterpStack.h
@@ -13,7 +13,9 @@
 #ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
 #define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
 
+#include "PrimType.h"
 #include 
+#include 
 
 namespace clang {
 namespace interp {
@@ -29,10 +31,17 @@
   /// Constructs a value in place on the top of the stack.
   template  void push(Tys &&... Args) {
 new (grow(aligned_size())) T(std::forward(Args)...);
+#ifndef NDEBUG
+ItemTypes.push_back(toPrimType());
+#endif
   }
 
   /// Returns the value from the top of the stack and removes it.
   template  T pop() {
+#ifndef NDEBUG
+assert(ItemTypes.back() == toPrimType());
+ItemTypes.pop_back();
+#endif
 auto *Ptr = &peek();
 auto Value = std::move(*Ptr);
 Ptr->~T();
@@ -42,6 +51,10 @@
 
   /// Discards the top value from the stack.
   template  void discard() {
+#ifndef NDEBUG
+assert(ItemTypes.back() == toPrimType());
+ItemTypes.pop_back();
+#endif
 auto *Ptr = &peek();
 Ptr->~T();
 shrink(aligned_size());
@@ -111,6 +124,43 @@
   StackChunk *Chunk = nullptr;
   /// Total size of the stack.
   size_t StackSize = 0;
+
+#ifndef NDEBUG
+  /// vector recording the type of data we pushed into the stack.
+  std::vector ItemTypes;
+
+  template  static constexpr PrimType toPrimType() {
+if constexpr (std::is_same::value)
+  return PT_Ptr;
+else if (std::is_same::value || std::is_same::value)
+  return PT_Bool;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Sint8;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Uint8;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Sint16;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Uint16;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Sint32;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Uint32;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Sint64;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Uint64;
+assert(false);
+  }
+#endif
 };
 
 } // namespace interp


Index: clang/lib/AST/Interp/InterpStack.h
===
--- clang/lib/AST/Interp/InterpStack.h
+++ clang/lib/AST/Interp/InterpStack.h
@@ -13,7 +13,9 @@
 #ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
 #define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
 
+#include "PrimType.h"
 #include 
+#include 
 
 namespace clang {
 namespace interp {
@@ -29,10 +31,17 @@
   /// Constructs a value in place on the top of the stack.
   template  void push(Tys &&... Args) {
 new (grow(aligned_size())) T(std::forward(Args)...);
+#ifndef NDEBUG
+ItemTypes.push_back(toPrimType());
+#endif
   }
 
   /// Returns the value from the top of the stack and removes it.
   template  T pop() {
+#ifndef NDEBUG
+assert(ItemTypes.back() == toPrimType());
+ItemTypes.pop_back();
+#endif
 auto *Ptr = &peek();
 auto Value = std::move(*Ptr);
 Ptr->~T();
@@ -42,6 +51,10 @@
 
   /// Discards the top value from the stack.
   template  void discard() {
+#ifndef NDEBUG
+assert(ItemTypes.back() == toPrimType());
+ItemTypes.pop_back();
+#endif
 auto *Ptr = &peek();
 Ptr->~T();
 shrink(aligned_size());
@@ -111,6 +124,43 @@
   StackChunk *Chunk = nullptr;
   /// Total size of the stack.
   size_t StackSize = 0;
+
+#ifndef NDEBUG
+  /// vector recording the type of data we pushed into the stack.
+  std::vector ItemTypes;
+
+  template  static constexpr PrimType toPrimType() {
+if constexpr (std::is_same::value)
+  return PT_Ptr;
+else if (std::is_same::value || std::is_same::value)
+  return PT_Bool;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Sint8;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Uint8;
+else if (std::is_same::value ||
+ std::is_same>::value)
+  return PT_Sint16;
+else if (std::is_same::

[PATCH] D133941: [clang][Interp] Record item types in InterpStack

2022-09-15 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

In D133941#3792330 , @erichkeane 
wrote:

> Can you clarify what the intent of this patch is?  Perhaps I'm just being 
> slow today, but I don't really get the intent here.

Consider:

  push(...);
  (lots of stuff)
  pop();

currently this would just work and give you an integer, but they value wouldn't 
make any sense. This patch would assert here since the value on the stack is 
not an integer, it's a pointer.
It basically adds a bit of type-safety back.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133941

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


[PATCH] D133934: [clang][Interp] Handle sizeof() expressions

2022-09-15 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 460409.

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

https://reviews.llvm.org/D133934

Files:
  clang/lib/AST/Interp/Boolean.h
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Opcodes.td
  clang/test/AST/Interp/literals.cpp

Index: clang/test/AST/Interp/literals.cpp
===
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -72,10 +72,30 @@
 constexpr const int* getIntPointer() {
   return &m;
 }
-//static_assert(getIntPointer() == &m, ""); TODO
-//static_assert(*getIntPointer() == 10, ""); TODO
+static_assert(getIntPointer() == &m, "");
+static_assert(*getIntPointer() == 10, "");
 
 constexpr int gimme(int k) {
   return k;
 }
-// static_assert(gimme(5) == 5, ""); TODO
+static_assert(gimme(5) == 5, "");
+
+namespace SizeOf {
+  constexpr int soint = sizeof(int);
+  constexpr int souint = sizeof(unsigned int);
+  static_assert(soint == souint, "");
+
+  static_assert(sizeof(&soint) == sizeof(void*), "");
+  static_assert(sizeof(&soint) == sizeof(nullptr), "");
+
+  static_assert(sizeof(long) == sizeof(unsigned long), "");
+  static_assert(sizeof(char) == sizeof(unsigned char), "");
+
+  constexpr int N = 4;
+  constexpr int arr[N] = {1,2,3,4};
+  static_assert(sizeof(arr) == N * sizeof(int), "");
+  static_assert(sizeof(arr) == N * sizeof(arr[0]), "");
+
+  constexpr bool arrB[N] = {true, true, true, true};
+  static_assert(sizeof(arrB) == N * sizeof(bool), "");
+};
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -427,11 +427,11 @@
 // TODO: Expand this to handle casts between more types.
 
 def FromCastTypeClass : TypeClass {
-  let Types = [Uint32, Sint32, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
 }
 
 def ToCastTypeClass : TypeClass {
-  let Types = [Uint32, Sint32, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
 }
 
 def Cast: Opcode {
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -80,6 +80,7 @@
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
   bool VisitInitListExpr(const InitListExpr *E);
   bool VisitConstantExpr(const ConstantExpr *E);
+  bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -281,7 +281,18 @@
 }
 
 template 
-bool ByteCodeExprGen::discard(const Expr *E) {
+bool ByteCodeExprGen::VisitUnaryExprOrTypeTraitExpr(
+const UnaryExprOrTypeTraitExpr *E) {
+
+  if (E->getKind() == UETT_SizeOf) {
+QualType ArgType = E->getTypeOfArgument();
+return this->emitConst(E, Ctx.getASTContext().getTypeSize(ArgType));
+  }
+
+  return false;
+}
+
+template  bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);
   return this->Visit(E);
 }
Index: clang/lib/AST/Interp/Boolean.h
===
--- clang/lib/AST/Interp/Boolean.h
+++ clang/lib/AST/Interp/Boolean.h
@@ -48,6 +48,10 @@
   Boolean operator~() const { return Boolean(true); }
 
   explicit operator unsigned() const { return V; }
+  explicit operator int8_t() const { return V; }
+  explicit operator uint8_t() const { return V; }
+  explicit operator int16_t() const { return V; }
+  explicit operator uint16_t() const { return V; }
   explicit operator int64_t() const { return V; }
   explicit operator uint64_t() const { return V; }
   explicit operator int() const { return V; }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133934: [clang][Interp] Handle sizeof() expressions

2022-09-15 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

Didn't now I could just get that information from the ASTContext, nice. Thanks.


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

https://reviews.llvm.org/D133934

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


[PATCH] D133934: [clang][Interp] Handle sizeof() expressions

2022-09-15 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:289
+QualType ArgType = E->getTypeOfArgument();
+return this->emitConst(E, Ctx.getASTContext().getTypeSize(ArgType));
+  }

erichkeane wrote:
> You probably want `getTypeSizeInChars`. `getTypeSize` returns it in bits, so 
> this would give the wrong answer.  You should probably add some tests to make 
> sure the values you are getting back are sane (like `char` is 1, etc).
Yeah, right. I explicitly didn't compare with fixed values when writing the 
tests so I don't run into the usual problems, but they wouldn't caught this 
problem...


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

https://reviews.llvm.org/D133934

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


[PATCH] D133934: [clang][Interp] Handle sizeof() expressions

2022-09-15 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 460412.

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

https://reviews.llvm.org/D133934

Files:
  clang/lib/AST/Interp/Boolean.h
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Opcodes.td
  clang/test/AST/Interp/literals.cpp

Index: clang/test/AST/Interp/literals.cpp
===
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -72,10 +72,33 @@
 constexpr const int* getIntPointer() {
   return &m;
 }
-//static_assert(getIntPointer() == &m, ""); TODO
-//static_assert(*getIntPointer() == 10, ""); TODO
+static_assert(getIntPointer() == &m, "");
+static_assert(*getIntPointer() == 10, "");
 
 constexpr int gimme(int k) {
   return k;
 }
-// static_assert(gimme(5) == 5, ""); TODO
+static_assert(gimme(5) == 5, "");
+
+namespace SizeOf {
+  constexpr int soint = sizeof(int);
+  constexpr int souint = sizeof(unsigned int);
+  static_assert(soint == souint, "");
+
+  static_assert(sizeof(&soint) == sizeof(void*), "");
+  static_assert(sizeof(&soint) == sizeof(nullptr), "");
+
+  static_assert(sizeof(long) == sizeof(unsigned long), "");
+  static_assert(sizeof(char) == sizeof(unsigned char), "");
+
+  constexpr int N = 4;
+  constexpr int arr[N] = {1,2,3,4};
+  static_assert(sizeof(arr) == N * sizeof(int), "");
+  static_assert(sizeof(arr) == N * sizeof(arr[0]), "");
+
+  constexpr bool arrB[N] = {true, true, true, true};
+  static_assert(sizeof(arrB) == N * sizeof(bool), "");
+
+  static_assert(sizeof(bool) == 1, "");
+  static_assert(sizeof(char) == 1, "");
+};
Index: clang/lib/AST/Interp/Opcodes.td
===
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -427,11 +427,11 @@
 // TODO: Expand this to handle casts between more types.
 
 def FromCastTypeClass : TypeClass {
-  let Types = [Uint32, Sint32, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
 }
 
 def ToCastTypeClass : TypeClass {
-  let Types = [Uint32, Sint32, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
 }
 
 def Cast: Opcode {
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -80,6 +80,7 @@
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
   bool VisitInitListExpr(const InitListExpr *E);
   bool VisitConstantExpr(const ConstantExpr *E);
+  bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -281,7 +281,19 @@
 }
 
 template 
-bool ByteCodeExprGen::discard(const Expr *E) {
+bool ByteCodeExprGen::VisitUnaryExprOrTypeTraitExpr(
+const UnaryExprOrTypeTraitExpr *E) {
+
+  if (E->getKind() == UETT_SizeOf) {
+QualType ArgType = E->getTypeOfArgument();
+return this->emitConst(
+E, Ctx.getASTContext().getTypeSizeInChars(ArgType).getQuantity());
+  }
+
+  return false;
+}
+
+template  bool ByteCodeExprGen::discard(const Expr *E) {
   OptionScope Scope(this, /*NewDiscardResult=*/true);
   return this->Visit(E);
 }
Index: clang/lib/AST/Interp/Boolean.h
===
--- clang/lib/AST/Interp/Boolean.h
+++ clang/lib/AST/Interp/Boolean.h
@@ -48,6 +48,10 @@
   Boolean operator~() const { return Boolean(true); }
 
   explicit operator unsigned() const { return V; }
+  explicit operator int8_t() const { return V; }
+  explicit operator uint8_t() const { return V; }
+  explicit operator int16_t() const { return V; }
+  explicit operator uint16_t() const { return V; }
   explicit operator int64_t() const { return V; }
   explicit operator uint64_t() const { return V; }
   explicit operator int() const { return V; }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D128248: [clang] Avoid an assertion in APValue::hasArrayFiller()

2022-06-28 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

If you apply e.g.

  @@ -10739,6 +10779,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const 
InitListExpr *E,
 << NumEltsToInit << ".\n");
  
 Result = APValue(APValue::UninitArray(), NumEltsToInit, NumElts);
  +  llvm::errs() << "Result " << &Result << ": " << Result.isArray() << "\n";
  
 // If the array was previously zero-initialized, preserve the
 // zero-initialized values.
  @@ -10764,6 +10805,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const 
InitListExpr *E,
   }
 }
  
  +  llvm::errs() << "Result " << &Result << ": " << Result.isArray() << "\n";
 if (!Result.hasArrayFiller())
   return Success;

and run the test case, the first added line prints `1` and the second one `0`. 
`Result` is being mutated when doing the in-place evaluation.

> I take that to mean that the expectation for this interface is that the 
> caller validates the APValue in the cases where it doesn't already know the 
> answer.

Sure, that was the other option.


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

https://reviews.llvm.org/D128248

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


[PATCH] D128248: [clang] Avoid an assertion in APValue::hasArrayFiller()

2022-06-30 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 441344.

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

https://reviews.llvm.org/D128248

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constexpr-array-init.cpp


Index: clang/test/SemaCXX/constexpr-array-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/constexpr-array-init.cpp
@@ -0,0 +1,19 @@
+
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+struct Foo {
+  int a; // expected-note {{subobject declared here}}
+  constexpr Foo()
+  : a(get_int()) {
+  }
+
+  constexpr int get_int() {
+return 5;
+  }
+};
+
+
+static constexpr Foo bar[2][1] = { // expected-error {{constexpr variable 
'bar' must be initialized by a constant expression}} \
+   // expected-note {{subobject of type 'int' 
is not initialized}}
+{{}},
+};
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10754,17 +10754,18 @@
   for (unsigned Index = 0; Index != NumEltsToInit; ++Index) {
 const Expr *Init =
 Index < E->getNumInits() ? E->getInit(Index) : FillerExpr;
-if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
- Info, Subobject, Init) ||
-!HandleLValueArrayAdjustment(Info, Init, Subobject,
- CAT->getElementType(), 1)) {
+if (Result.isArray() &&
+(!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, 
Subobject,
+  Init) ||
+ !HandleLValueArrayAdjustment(Info, Init, Subobject,
+  CAT->getElementType(), 1))) {
   if (!Info.noteFailure())
 return false;
   Success = false;
 }
   }
 
-  if (!Result.hasArrayFiller())
+  if (!Result.isArray() || !Result.hasArrayFiller())
 return Success;
 
   // If we get here, we have a trivial filler, which we can just evaluate


Index: clang/test/SemaCXX/constexpr-array-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/constexpr-array-init.cpp
@@ -0,0 +1,19 @@
+
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+struct Foo {
+  int a; // expected-note {{subobject declared here}}
+  constexpr Foo()
+  : a(get_int()) {
+  }
+
+  constexpr int get_int() {
+return 5;
+  }
+};
+
+
+static constexpr Foo bar[2][1] = { // expected-error {{constexpr variable 'bar' must be initialized by a constant expression}} \
+   // expected-note {{subobject of type 'int' is not initialized}}
+{{}},
+};
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10754,17 +10754,18 @@
   for (unsigned Index = 0; Index != NumEltsToInit; ++Index) {
 const Expr *Init =
 Index < E->getNumInits() ? E->getInit(Index) : FillerExpr;
-if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
- Info, Subobject, Init) ||
-!HandleLValueArrayAdjustment(Info, Init, Subobject,
- CAT->getElementType(), 1)) {
+if (Result.isArray() &&
+(!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject,
+  Init) ||
+ !HandleLValueArrayAdjustment(Info, Init, Subobject,
+  CAT->getElementType(), 1))) {
   if (!Info.noteFailure())
 return false;
   Success = false;
 }
   }
 
-  if (!Result.hasArrayFiller())
+  if (!Result.isArray() || !Result.hasArrayFiller())
 return Success;
 
   // If we get here, we have a trivial filler, which we can just evaluate
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D128248: [clang] Avoid an assertion in APValue::hasArrayFiller()

2022-06-30 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

I added the `isArray()` check in both places now, but the first one is not 
necessary for the test case (at least).


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

https://reviews.llvm.org/D128248

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


[PATCH] D128248: [clang] Avoid an assertion in APValue::hasArrayFiller()

2022-06-30 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 441379.

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

https://reviews.llvm.org/D128248

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constexpr-array-init.cpp


Index: clang/test/SemaCXX/constexpr-array-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/constexpr-array-init.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+// FIXME: This code should compile without errors but as of right now doesn't.
+//   We're only testing that clang doesn't crash or run into an assertion.
+struct Foo {
+  int a; // expected-note {{subobject declared here}}
+  constexpr Foo()
+  : a(get_int()) {
+  }
+
+  constexpr int get_int() {
+return 5;
+  }
+};
+
+static constexpr Foo bar[2][1] = { // expected-error {{constexpr variable 
'bar' must be initialized by a constant expression}} \
+   // expected-note {{subobject of type 'int' 
is not initialized}}
+{{}},
+};
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10754,17 +10754,18 @@
   for (unsigned Index = 0; Index != NumEltsToInit; ++Index) {
 const Expr *Init =
 Index < E->getNumInits() ? E->getInit(Index) : FillerExpr;
-if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
- Info, Subobject, Init) ||
-!HandleLValueArrayAdjustment(Info, Init, Subobject,
- CAT->getElementType(), 1)) {
+if (Result.isArray() &&
+(!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, 
Subobject,
+  Init) ||
+ !HandleLValueArrayAdjustment(Info, Init, Subobject,
+  CAT->getElementType(), 1))) {
   if (!Info.noteFailure())
 return false;
   Success = false;
 }
   }
 
-  if (!Result.hasArrayFiller())
+  if (!Result.isArray() || !Result.hasArrayFiller())
 return Success;
 
   // If we get here, we have a trivial filler, which we can just evaluate
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -175,6 +175,8 @@
   emitted as a dynamic initializer. Previously the variable would
   incorrectly be zero-initialized. In contexts where a dynamic
   initializer is not allowed this is now diagnosed as an error.
+- Fixed an assertion failure when evaluating a constexpr constructor
+  in an array initializer.
 
 Improvements to Clang's diagnostics
 ^^^


Index: clang/test/SemaCXX/constexpr-array-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/constexpr-array-init.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+// FIXME: This code should compile without errors but as of right now doesn't.
+//   We're only testing that clang doesn't crash or run into an assertion.
+struct Foo {
+  int a; // expected-note {{subobject declared here}}
+  constexpr Foo()
+  : a(get_int()) {
+  }
+
+  constexpr int get_int() {
+return 5;
+  }
+};
+
+static constexpr Foo bar[2][1] = { // expected-error {{constexpr variable 'bar' must be initialized by a constant expression}} \
+   // expected-note {{subobject of type 'int' is not initialized}}
+{{}},
+};
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10754,17 +10754,18 @@
   for (unsigned Index = 0; Index != NumEltsToInit; ++Index) {
 const Expr *Init =
 Index < E->getNumInits() ? E->getInit(Index) : FillerExpr;
-if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
- Info, Subobject, Init) ||
-!HandleLValueArrayAdjustment(Info, Init, Subobject,
- CAT->getElementType(), 1)) {
+if (Result.isArray() &&
+(!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject,
+  Init) ||
+ !HandleLValueArrayAdjustment(Info, Init, Subobject,
+  CAT->getElementType(), 1))) {
   if (!Info.noteFailure())
 return false;
   Success = false;
 }
   }
 
-  if (!Result.hasArrayFiller())
+  if (!Result.isArray() || !Result.hasArrayFiller())
 return Success;
 
   // If we get here, we have a trivial filler, which we can just evaluate
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -175,6 +175,8 @@
   emitted as a dynamic initializer.

[PATCH] D128248: [clang] Avoid an assertion in APValue::hasArrayFiller()

2022-07-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder marked 2 inline comments as done.
tbaeder added a comment.

In D128248#3622775 , @shafik wrote:

> LGTM after addressing all of Aaron's comments.

I've already addressed them; did you miss the update or are you saying I 
haven't addressed them properly?


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

https://reviews.llvm.org/D128248

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


[PATCH] D121201: [clang] Merge the SourceRange into ParsedAttributes

2022-03-24 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG711e3a569167: [clang][parse] Move source range into 
ParsedAttibutesView (authored by tbaeder).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D121201

Files:
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseCXXInlineMethods.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Parse/ParseOpenMP.cpp
  clang/lib/Parse/ParsePragma.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/SemaStmtAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/SemaOpenCL/address-spaces.cl

Index: clang/test/SemaOpenCL/address-spaces.cl
===
--- clang/test/SemaOpenCL/address-spaces.cl
+++ clang/test/SemaOpenCL/address-spaces.cl
@@ -258,7 +258,7 @@
 
 void func_multiple_addr2(void) {
   typedef __private int private_int_t;
-  __private __attribute__((opencl_global)) int var1;   // expected-error {{multiple address spaces specified for type}} \
+  __attribute__((opencl_global)) __private int var1;   // expected-error {{multiple address spaces specified for type}} \
// expected-error {{function scope variable cannot be declared in global address space}}
   __private __attribute__((opencl_global)) int *var2;  // expected-error {{multiple address spaces specified for type}}
   __attribute__((opencl_global)) private_int_t var3;   // expected-error {{multiple address spaces specified for type}}
Index: clang/lib/Sema/SemaType.cpp
===
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -368,7 +368,8 @@
 };
 
 static void processTypeAttrs(TypeProcessingState &state, QualType &type,
- TypeAttrLocation TAL, ParsedAttributesView &attrs);
+ TypeAttrLocation TAL,
+ const ParsedAttributesView &attrs);
 
 static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
QualType &type);
@@ -8149,7 +8150,12 @@
 
 static void processTypeAttrs(TypeProcessingState &state, QualType &type,
  TypeAttrLocation TAL,
- ParsedAttributesView &attrs) {
+ const ParsedAttributesView &attrs) {
+
+  state.setParsedNoDeref(false);
+  if (attrs.empty())
+return;
+
   // Scan through and apply attributes to this type where it makes sense.  Some
   // attributes (such as __address_space__, __vector_size__, etc) apply to the
   // type, but others can be present in the type specifiers even though they
@@ -8159,9 +8165,6 @@
   // sure we visit every element once. Copy the attributes list, and iterate
   // over that.
   ParsedAttributesView AttrsCopy{attrs};
-
-  state.setParsedNoDeref(false);
-
   for (ParsedAttr &attr : AttrsCopy) {
 
 // Skip attributes that were marked to be invalid.
Index: clang/lib/Sema/SemaStmtAttr.cpp
===
--- clang/lib/Sema/SemaStmtAttr.cpp
+++ clang/lib/Sema/SemaStmtAttr.cpp
@@ -495,8 +495,7 @@
   }
 }
 
-void Sema::ProcessStmtAttributes(Stmt *S,
- const ParsedAttributesWithRange &InAttrs,
+void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,
  SmallVectorImpl &OutAttrs) {
   for (const ParsedAttr &AL : InAttrs) {
 if (const Attr *A = ProcessStmtAttribute(*this, S, AL, InAttrs.Range))
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -587,7 +587,7 @@
   return AttributedStmt::Create(Context, AttrsLoc, Attrs, SubStmt);
 }
 
-StmtResult Sema::ActOnAttributedStmt(const ParsedAttributesWithRange &Attrs,
+StmtResult Sema::ActOnAttributedStmt(const ParsedAttributes &Attrs,
  Stmt *SubStmt) {
   SmallVector SemanticAttrs;
   ProcessStmtAttributes(SubStmt, Attrs, SemanticAttrs);
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -2641,12 +2641,11 @@
 /// example:
 ///class foo : public bar, virtual private baz {
 /// 'public bar' and 'virtual private baz' are each

[PATCH] D122659: [clang][preprocessor] Allow calling DumpToken() on annotation tokens

2022-03-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added a reviewer: aaron.ballman.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The `getSpelling()` call otherwise ultimately runs into an assertion because 
`getLength()` is called on an annotation token.

Just ran into this when debugging using `-dump-tokens`.
Sorry I can't really find a better reviewer, the rest of that function seems to 
be pretty ancient.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122659

Files:
  clang/lib/Lex/Preprocessor.cpp


Index: clang/lib/Lex/Preprocessor.cpp
===
--- clang/lib/Lex/Preprocessor.cpp
+++ clang/lib/Lex/Preprocessor.cpp
@@ -232,8 +232,10 @@
 }
 
 void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
-  llvm::errs() << tok::getTokenName(Tok.getKind()) << " '"
-   << getSpelling(Tok) << "'";
+  llvm::errs() << tok::getTokenName(Tok.getKind());
+
+  if (!Tok.isAnnotation())
+llvm::errs() << " '" << getSpelling(Tok) << "'";
 
   if (!DumpFlags) return;
 


Index: clang/lib/Lex/Preprocessor.cpp
===
--- clang/lib/Lex/Preprocessor.cpp
+++ clang/lib/Lex/Preprocessor.cpp
@@ -232,8 +232,10 @@
 }
 
 void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
-  llvm::errs() << tok::getTokenName(Tok.getKind()) << " '"
-   << getSpelling(Tok) << "'";
+  llvm::errs() << tok::getTokenName(Tok.getKind());
+
+  if (!Tok.isAnnotation())
+llvm::errs() << " '" << getSpelling(Tok) << "'";
 
   if (!DumpFlags) return;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122659: [clang][preprocessor] Allow calling DumpToken() on annotation tokens

2022-03-30 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 419073.

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

https://reviews.llvm.org/D122659

Files:
  clang/lib/Lex/Preprocessor.cpp


Index: clang/lib/Lex/Preprocessor.cpp
===
--- clang/lib/Lex/Preprocessor.cpp
+++ clang/lib/Lex/Preprocessor.cpp
@@ -232,8 +232,10 @@
 }
 
 void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
-  llvm::errs() << tok::getTokenName(Tok.getKind()) << " '"
-   << getSpelling(Tok) << "'";
+  llvm::errs() << tok::getTokenName(Tok.getKind());
+
+  if (!Tok.isAnnotation())
+llvm::errs() << " '" << getSpelling(Tok) << "'";
 
   if (!DumpFlags) return;
 


Index: clang/lib/Lex/Preprocessor.cpp
===
--- clang/lib/Lex/Preprocessor.cpp
+++ clang/lib/Lex/Preprocessor.cpp
@@ -232,8 +232,10 @@
 }
 
 void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
-  llvm::errs() << tok::getTokenName(Tok.getKind()) << " '"
-   << getSpelling(Tok) << "'";
+  llvm::errs() << tok::getTokenName(Tok.getKind());
+
+  if (!Tok.isAnnotation())
+llvm::errs() << " '" << getSpelling(Tok) << "'";
 
   if (!DumpFlags) return;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119221: [clang][lexer] Allow u8 character literal prefixes in C2x

2022-03-31 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.
Herald added a project: All.

Is there anything missing here?


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

https://reviews.llvm.org/D119221

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


[PATCH] D122885: [clang] Draft: Implement P1703R1

2022-04-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, iains, urnathan, ChuanqiXu.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

As in: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1703r1.html

Posting this mostly to get some feedback on the general path taken.

>From reading the paper, I understand that the preprocessor should gain a 
>"import-keyword" token, but that is already taken by the GNU `#import` 
>extension.

The implementation here starts converting newlines to `eod` tokens when seeing 
a `export` or `import` token. However, that means ignoring the `eod` tokens 
when parsing an export block, an exported declaration or a non-header-unit 
module import.

Let me know what you think.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122885

Files:
  clang/include/clang/Basic/DiagnosticLexKinds.td
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Lex/Preprocessor.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/Parser.cpp
  clang/test/CXX/cpp/cpp.module/p1.cpp
  clang/test/CXX/lex/lex.pptoken/p3-2a.cpp
  clang/test/Modules/P1703R1.cpp

Index: clang/test/Modules/P1703R1.cpp
===
--- /dev/null
+++ clang/test/Modules/P1703R1.cpp
@@ -0,0 +1,103 @@
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: mkdir -p %t/system
+// RUN: split-file %s %t
+// RUN: cd %t
+
+// RUN: %clang_cc1 -std=c++20 -emit-header-unit \
+// RUN: -xc++-header header.h -o header.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-header-unit -isystem system \
+// RUN: -xc++-system-header system-header.h -o system/system-header.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface dummy.cpp -o dummy.pcm
+
+// RUN: %clang_cc1 -std=c++20 -fmodule-file=header.pcm \
+// RUN: -fmodule-file=system/system-header.pcm \
+// RUN: -fmodule-file=dummy.pcm \
+// RUN: -emit-module-interface -isystem system \
+// RUN: main.cpp -verify
+
+//--- header.h
+int foo(int);
+
+//--- system/system-header.h
+int foo2(int);
+
+//--- dummy.cpp
+export module dummy;
+
+//--- main.cpp
+export module main;
+#define IMPORT import
+#define EXPORT export
+#define HEADER "header.h"
+#define SYSTEM_HEADER 
+#define SEMI ;
+
+
+/// Fine.
+import "header.h";
+export import "header.h";
+
+
+import
+"header.h";// expected-error {{expected a module name after 'import'}}
+export import
+"header.h"; // expected-error {{expected a module name after 'import'}}
+export
+import "header.h"; // expected-error {{expected a module name after 'import'}}
+
+import "header.h"; import "header.h"; // expected-error {{import keyword must be at start of line}}
+  // expected-error@-1 {{extra tokens after module import}}
+
+import "header.h" SEMI // expected-error {{semicolon terminating header import declaration cannot be produced by a macro}}
+IMPORT "header.h"; // expected-error {{import keyword cannot be produced by a macro}}
+EXPORT import "header.h"; // expected-error {{export keyword cannot be produced by a macro}}
+import HEADER; /// Fine.
+
+
+import ;
+export import ;
+
+import
+; // expected-error {{expected a module name after 'import'}}
+IMPORT ;// expected-error {{import keyword cannot be produced by a macro}}
+EXPORT import ;// expected-error {{export keyword cannot be produced by a macro}}
+import SYSTEM_HEADER;
+
+
+
+/// Normal module imports are unaffected
+import dummy;
+import
+dummy;
+export
+import
+dummy;
+export import
+dummy;
+export
+import dummy;
+import dummy; import dummy;
+
+
+
+// TODO: The diagnostics here could be much better.
+export
+import "header.h"; // expected-error {{expected a module name after 'import'}}
+
+export import
+"header.h" // expected-error {{expected a module name after 'import'}}
+
+
+export void foo() {}
+export void
+baz(){}
+export
+void bar(){}
+
+export {
+  void a(){}
+}
Index: clang/test/CXX/lex/lex.pptoken/p3-2a.cpp
===
--- clang/test/CXX/lex/lex.pptoken/p3-2a.cpp
+++ clang/test/CXX/lex/lex.pptoken/p3-2a.cpp
@@ -56,26 +56,3 @@
 #define HEADER 
 // CHECK: import ;
 import HEADER;
-
-// CHECK: import ;
-import <
-foo
-  bar
->;
-
-// CHECK: import{{$}}
-// CHECK: {{^}};
-import
-<
-foo
-  bar
->;
-
-// CHECK: import{{$}}
-// CHECK: {{^}};
-import
-;
-
-#define IMPORT import 
-// CHECK: import ;
-IMPORT;
Index: clang/test/CXX/cpp/cpp.module/p1.cpp
===
--- clang/test/CXX/cpp/cpp.module/p1.cpp
+++ clang/test/CXX/cpp/cpp.module/p1.cpp
@@ -5,11 +5,11 @@
 // expected-error@+1 {{semicolon terminating header import declaration cannot be produced by a macro}}
 import "empty.h" SEMI // CHECK: import attrs.{{.*}};
 
-#define IMPORT import "empty.h"
-IMPORT; // CHECK: import attrs.{{.*}};
+#define IMPORT "empty.h"
+import IMPORT; // CHECK: import attrs.{{.*}};

[PATCH] D122885: [clang] Draft: Implement P1703R1

2022-04-04 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

In D122885#3426070 , @urnathan wrote:

> Ah, I'd had a thinko about what 1703 was.  that's superseded by 
> p1757wg21.link/p1857.  That's what is needed.  (your patch 
> makes more sense in the 1703 context)

Ha, okay. Yes, that makes more sense. Both papers are linked in 
https://clang.llvm.org/cxx_status.html. Sorry for the confusion, I'll have a 
look at 1857R3 instead.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D122885

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


[PATCH] D122885: [clang] Draft: Implement P1703R1

2022-04-05 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

What patches are you talking about exactly?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D122885

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


[PATCH] D130791: [clang] Short-circuit trivial constexpr array constructors

2022-07-29 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, rsmith.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

As discussed in https://github.com/llvm/llvm-project/issues/56774


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130791

Files:
  clang/lib/AST/ExprConstant.cpp


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10833,6 +10833,9 @@
 if (FinalSize == 0)
   return true;
 
+bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+Info, E->getExprLoc(), E->getConstructor(),
+E->requiresZeroInitialization());
 LValue ArrayElt = Subobject;
 ArrayElt.addArray(Info, E, CAT);
 // We do the whole initialization in two passes, first for just one 
element,
@@ -10856,19 +10859,26 @@
 for (unsigned I = OldElts; I < N; ++I)
   Value->getArrayInitializedElt(I) = Filler;
 
-  // Initialize the elements.
-  for (unsigned I = OldElts; I < N; ++I) {
-if (!VisitCXXConstructExpr(E, ArrayElt,
-   &Value->getArrayInitializedElt(I),
-   CAT->getElementType()) ||
-!HandleLValueArrayAdjustment(Info, E, ArrayElt,
- CAT->getElementType(), 1))
-  return false;
-// When checking for const initilization any diagnostic is considered
-// an error.
-if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
-!Info.keepEvaluatingAfterFailure())
-  return false;
+  if (HasTrivialConstructor && N == FinalSize) {
+// If we have a trivial constructor, only evaluate it once and copy
+// the result into all the array elements.
+APValue &FirstResult = Value->getArrayInitializedElt(0);
+for (unsigned I = OldElts; I < FinalSize; ++I)
+  Value->getArrayInitializedElt(I) = FirstResult;
+  } else {
+for (unsigned I = OldElts; I < N; ++I) {
+  if (!VisitCXXConstructExpr(E, ArrayElt,
+ &Value->getArrayInitializedElt(I),
+ CAT->getElementType()) ||
+  !HandleLValueArrayAdjustment(Info, E, ArrayElt,
+   CAT->getElementType(), 1))
+return false;
+  // When checking for const initilization any diagnostic is considered
+  // an error.
+  if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
+  !Info.keepEvaluatingAfterFailure())
+return false;
+}
   }
 }
 


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10833,6 +10833,9 @@
 if (FinalSize == 0)
   return true;
 
+bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+Info, E->getExprLoc(), E->getConstructor(),
+E->requiresZeroInitialization());
 LValue ArrayElt = Subobject;
 ArrayElt.addArray(Info, E, CAT);
 // We do the whole initialization in two passes, first for just one element,
@@ -10856,19 +10859,26 @@
 for (unsigned I = OldElts; I < N; ++I)
   Value->getArrayInitializedElt(I) = Filler;
 
-  // Initialize the elements.
-  for (unsigned I = OldElts; I < N; ++I) {
-if (!VisitCXXConstructExpr(E, ArrayElt,
-   &Value->getArrayInitializedElt(I),
-   CAT->getElementType()) ||
-!HandleLValueArrayAdjustment(Info, E, ArrayElt,
- CAT->getElementType(), 1))
-  return false;
-// When checking for const initilization any diagnostic is considered
-// an error.
-if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
-!Info.keepEvaluatingAfterFailure())
-  return false;
+  if (HasTrivialConstructor && N == FinalSize) {
+// If we have a trivial constructor, only evaluate it once and copy
+// the result into all the array elements.
+APValue &FirstResult = Value->getArrayInitializedElt(0);
+for (unsigned I = OldElts; I < FinalSize; ++I)
+  Value->getArrayInitializedElt(I) = FirstResult;
+  } else {
+for (unsigned I = OldElts; I < N; ++I) {
+  if (!VisitCXXConstructExpr(E, ArrayElt,
+ &Value->getArrayInitializedElt(I),
+ CAT->getElementType()) ||
+  !HandleLValueArrayAdjustment(Info, E, ArrayElt,
+   CAT->getElementType(), 1))
+return false;
+  // When checking f

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added a reviewer: aaron.ballman.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

For

  c++
  static constexpr m = 10;
  static_assert(m == 11);

the output is before:

  ./test.cpp:2:1: error: static_assert failed due to requirement 'm == 11'
  static_assert(m == 11);
  ^ ~~~
  1 error generated.

and after:

  ./test.cpp:2:1: error: static assertion failed due to requirement 'm == 11'
  static_assert(m == 11);
  ^ ~~~
  ./test.cpp:2:15: note: left-hand side of operator '==' evaluates to '10'
  static_assert(m == 11);
^
  1 error generated.

The patch adds a new function `Sema::DiagnoseStaticAssertDetails()`, which 
currently only handles binary operators with an integer literal on one side and 
a non-integer literal on the other side. This is intentionally kept simple, but 
can be improved incrementally over time of course.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130894

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp

Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to '1'}}
   }
 }
 
Index: clang/test/PCH/cxx-templates.cpp
===
--- clang/test/PCH/cxx-templates.cpp
+++ clang/test/PCH/cxx-templates.cpp
@@ -167,7 +167,8 @@
   // This used to mark 'f' invalid without producing any diagnostic. That's a
   // little hard to detect, but we can make sure that constexpr evaluation
   // fails when it should.
-  static_assert(A().f() == 1); // expected-error {{static assertion failed}}
+  static_assert(A().f() == 1); // expected-error {{static assertion failed}} \
+// expected-note {{left-hand side of operator '==' evaluates to '0'}}
 #endif
 }
 
Index: clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
===
--- clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
+++ clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
@@ -40,8 +40,10 @@
 
 template constexpr auto x = [...z = a] (auto F) { return F(z...); };
 static_assert(x<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 123);
-static_assert(x<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}}
+static_assert(x<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}} \
+  // expected-note {{evaluates to '123'}}
 
 template constexpr auto y = [z = a...] (auto F) { return F(z...); }; // expected-error {{must appear before the name of the capture}}
 static_assert(y<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 123);
-static_assert(y<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}}
+static_assert(y<1,2,3>([](int a, int b, int c)

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:16656
&& !isa(InnerCond)) {
+
 Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)

Oops, this needs to go.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130894

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


[PATCH] D130906: [clang] format string checking for conpile-time evaluated str literal

2022-08-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/Sema/SemaChecking.cpp:8504
 return SLCT_UncheckedLiteral;
+  Expr::EvalResult Result;
+  if (E->EvaluateAsRValue(Result, S.Context)) {

A comment above this line would be helpful. Would also visually separate it 
from the `return` above, which just confused me.



Comment at: clang/lib/Sema/SemaChecking.cpp:8507
+if (Result.Val.isLValue()) {
+  auto *LVE = Result.Val.getLValueBase().dyn_cast();
+  if (LVE && LVE->getStmtClass() == Stmt::StringLiteralClass) {

I think you should be able to unify the two `if` statements.

Can you not `dyn_cast_or_null(Result.Val.getLValueBase())` here 
instead of casting to `Expr*` and checking the `StmtClass`?



Comment at: clang/test/Sema/format-strings-scanf.c:235
   scanf(0 ? "%s" : "%d", i); // no warning
-  scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char 
*'}}
+  scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char 
*'}} \
+ // expected-note{{format string is defined here}}

inclyc wrote:
> These new notes are FixIt hints, looks much better than before.
Can you show some sample output?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130906

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


[PATCH] D130791: [clang] Short-circuit trivial constexpr array constructors

2022-08-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

In D130791#3692071 , @dblaikie wrote:

> also: What about zero length arrays? (which are supported as an extension) - 
> this change would cause failures that wouldn't be emitted in the old code?

There's a `if (FinalSize == 0) return true;` case above, so this code will 
never be reached for zero-length arrays. That loop here is pretty confusing... 
`OldElts` is either zero (for the first iteration), or one (for the second 
iteration, where `N == FinalSize`). I tried to untangle this, but it doesn't 
work very well since the `APValue` we pass to `VisitCXXConstructExpr()` must be 
in an array `APValue`...

As for testing: I didn't include a test because of what you two mentioned, I 
can't really test that a test case finished in under X seconds...




Comment at: clang/lib/AST/ExprConstant.cpp:10836-10838
+bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+Info, E->getExprLoc(), E->getConstructor(),
+E->requiresZeroInitialization());

aaron.ballman wrote:
> The big question this raises for me is: will this cause constexpr to fail 
> because of the note diagnostics when the type does not have a trivial default 
> constructor? Or does this just bump the failure up a bit so that we fail 
> before we start walking over the array elements?
I can't come up with an example that would make this fail, or fail differently 
than it did before. For a constructor that is not marked `constexpr` and where 
`CheckTrivialDefaultConstructor` returns `false`, the first 
`VisitCXXConstructExpr` will return `false` and no diagnostic will be emitted. 
In the cases I tried, `Info.EvalStatus.Diag` is `nullptr` anyway, so yeah. If 
it did emit a diagnostic, I would assume that the failure just happens a little 
early, yes.

The alternative would be to try to integrate the 
`CheckTrivialDefaultConstructor` call into the loop, but I'm not a fan of that 
loop anyway :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130791

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


[PATCH] D130791: [clang] Short-circuit trivial constexpr array constructors

2022-08-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449182.

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

https://reviews.llvm.org/D130791

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10833,6 +10833,9 @@
 if (FinalSize == 0)
   return true;
 
+bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+Info, E->getExprLoc(), E->getConstructor(),
+E->requiresZeroInitialization());
 LValue ArrayElt = Subobject;
 ArrayElt.addArray(Info, E, CAT);
 // We do the whole initialization in two passes, first for just one 
element,
@@ -10856,19 +10859,26 @@
 for (unsigned I = OldElts; I < N; ++I)
   Value->getArrayInitializedElt(I) = Filler;
 
-  // Initialize the elements.
-  for (unsigned I = OldElts; I < N; ++I) {
-if (!VisitCXXConstructExpr(E, ArrayElt,
-   &Value->getArrayInitializedElt(I),
-   CAT->getElementType()) ||
-!HandleLValueArrayAdjustment(Info, E, ArrayElt,
- CAT->getElementType(), 1))
-  return false;
-// When checking for const initilization any diagnostic is considered
-// an error.
-if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
-!Info.keepEvaluatingAfterFailure())
-  return false;
+  if (HasTrivialConstructor && N == FinalSize) {
+// If we have a trivial constructor, only evaluate it once and copy
+// the result into all the array elements.
+APValue &FirstResult = Value->getArrayInitializedElt(0);
+for (unsigned I = OldElts; I < FinalSize; ++I)
+  Value->getArrayInitializedElt(I) = FirstResult;
+  } else {
+for (unsigned I = OldElts; I < N; ++I) {
+  if (!VisitCXXConstructExpr(E, ArrayElt,
+ &Value->getArrayInitializedElt(I),
+ CAT->getElementType()) ||
+  !HandleLValueArrayAdjustment(Info, E, ArrayElt,
+   CAT->getElementType(), 1))
+return false;
+  // When checking for const initilization any diagnostic is considered
+  // an error.
+  if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
+  !Info.keepEvaluatingAfterFailure())
+return false;
+}
   }
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -55,6 +55,9 @@
 - Fixes an accepts-invalid bug in C when using a ``_Noreturn`` function
   specifier on something other than a function declaration. This fixes
   `Issue 56800 `_.
+- Improve compile-times with large dynamic array allocations with trivial
+  constructors. This fixes
+  `Issue 56774`_.
 
 Improvements to Clang's diagnostics
 ^^^


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10833,6 +10833,9 @@
 if (FinalSize == 0)
   return true;
 
+bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+Info, E->getExprLoc(), E->getConstructor(),
+E->requiresZeroInitialization());
 LValue ArrayElt = Subobject;
 ArrayElt.addArray(Info, E, CAT);
 // We do the whole initialization in two passes, first for just one element,
@@ -10856,19 +10859,26 @@
 for (unsigned I = OldElts; I < N; ++I)
   Value->getArrayInitializedElt(I) = Filler;
 
-  // Initialize the elements.
-  for (unsigned I = OldElts; I < N; ++I) {
-if (!VisitCXXConstructExpr(E, ArrayElt,
-   &Value->getArrayInitializedElt(I),
-   CAT->getElementType()) ||
-!HandleLValueArrayAdjustment(Info, E, ArrayElt,
- CAT->getElementType(), 1))
-  return false;
-// When checking for const initilization any diagnostic is considered
-// an error.
-if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
-!Info.keepEvaluatingAfterFailure())
-  return false;
+  if (HasTrivialConstructor && N == FinalSize) {
+// If we have a trivial constructor, only evaluate it once and copy
+// the result into all the array elements.
+APValue &FirstResult = Value->getArrayInitializedElt(0);
+for (unsigned I = OldElts; I < FinalSize; ++I)
+  Value->getArrayInitializedEl

[PATCH] D130906: [clang] format string checking for conpile-time evaluated str literal

2022-08-01 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/Sema/SemaChecking.cpp:8507
+if (Result.Val.isLValue()) {
+  auto *LVE = Result.Val.getLValueBase().dyn_cast();
+  if (LVE && LVE->getStmtClass() == Stmt::StringLiteralClass) {

inclyc wrote:
> tbaeder wrote:
> > I think you should be able to unify the two `if` statements.
> > 
> > Can you not `dyn_cast_or_null(Result.Val.getLValueBase())` 
> > here instead of casting to `Expr*` and checking the `StmtClass`?
> `LValueBase` seems to be a wrapper of a pointer that has its own dyn_cast 
> method.
> 
> I have changed code here like this, but it cannot compile
> ```
> auto *MaybeStringLiteral =
> dyn_cast_or_null(Result.Val.getLValueBase());
> if (MaybeStringLiteral) {
>   return checkFormatStringExpr(S, MaybeStringLiteral, Args, APK, 
> format_idx,
>firstDataArg, Type, CallType,
>/*InFunctionCall*/ false, CheckedVarArgs,
>UncoveredArg, Offset);
> }
> ```
> 
> ```
> /llvm-project/llvm/include/llvm/Support/Casting.h:64:53: error: 
> type 'clang::StringLiteral *' cannot be used prior to '::' because it has no 
> members
>   static inline bool doit(const From &Val) { return To::classof(&Val); }
> ```
Ah, shame. This ends up calling `dyn_cast` on a `llvm::Pointerunion` as far as 
I can see, which seems to return `nullptr` in case the cast is unsuccessful 
anyway, so you could try just exploiting that: 
https://llvm.org/doxygen/classllvm_1_1PointerUnion.html#a9147352f78d98ee246f25d3300e0aaba



Comment at: clang/test/Sema/format-strings-scanf.c:235
   scanf(0 ? "%s" : "%d", i); // no warning
-  scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char 
*'}}
+  scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char 
*'}} \
+ // expected-note{{format string is defined here}}

inclyc wrote:
> tbaeder wrote:
> > inclyc wrote:
> > > These new notes are FixIt hints, looks much better than before.
> > Can you show some sample output?
> Source:
> ```
> // sample.cpp
> #include 
> 
> int main() {
>   int *i;
>   scanf(1 ? "%s %d" : "%d", i);
> }
> ```
> 
> previous version:
> ```
> sample.cpp:5:29: warning: format specifies type 'char *' but the argument has 
> type 'int *' [-Wformat]
>   scanf(1 ? "%s %d" : "%d", i);
>  ~~ ^
>  %d
> sample.cpp:5:18: warning: more '%' conversions than data arguments 
> [-Wformat-insufficient-args]
>   scanf(1 ? "%s %d" : "%d", i);
> ~^
> 2 warnings generated.
> ```
> 
> this patch highlights ` cond ? T : F` expressions:
> 
> ```
> sample.cpp:5:29: warning: format specifies type 'char *' but the argument has 
> type 'int *' [-Wformat]
>   scanf(1 ? "%s %d" : "%d", i);
> ~~  ^
> sample.cpp:5:14: note: format string is defined here
>   scanf(1 ? "%s %d" : "%d", i);
>  ^~
>  %d
> sample.cpp:5:9: warning: more '%' conversions than data arguments 
> [-Wformat-insufficient-args]
>   scanf(1 ? "%s %d" : "%d", i);
> ^~
> sample.cpp:5:18: note: format string is defined here
>   scanf(1 ? "%s %d" : "%d", i);
> ~^
> 2 warnings generated.
> ```
> 
Alright, might be a bit verbose but I agree that it is useful.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130906

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


[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-02 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449199.

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

https://reviews.llvm.org/D130894

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp

Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to '1'}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert-cxx17.cpp
===
--- clang/test/SemaCXX/static-assert-cxx17.cpp
+++ clang/test/SemaCXX/static-assert-cxx17.cpp
@@ -88,7 +88,8 @@
   static_assert(typename T::T(0));
   // expected-error@-1{{static assertion failed due to requirement 'int(0)'}}
   static_assert(sizeof(X) == 0);
-  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X) == 0'}}
+  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X) == 0'}} \
+  // expected-note@-1 {{evaluates to '8'}}
   static_assert((const X *)nullptr);
   // expected-error@-1{{static assertion failed due to requirement '(const X *)nullptr'}}
   static_assert(static_cast *>(nullptr));
@@ -96,7 +97,8 @@
   static_assert((const X[]){} == nullptr);
   // expected-error@-1{{static assertion failed due to requirement '(const X[0]){} == nullptr'}}
   static_assert(sizeof(X().X::~X())>) == 0);
-  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X) == 0'}}
+  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X) == 0'}} \
+  // expected-note@-1 {{evaluates to '8'}}
   static_assert(constexpr_return_false());
   // expected-error@-1{{static assertion failed due to requirement 'constexpr_return_false()'}}
 }
Index: clang/test/Parser/objc-static-assert.mm
===
--- clang/test/Parser/objc-static-assert.mm
+++ clang/test/Parser/objc-static-assert.mm
@@ -26,7 +26,8 @@
 
   static_assert(a, ""); // expected-error {{static assertion expression is not an integral constant expression}}
   static_assert(sizeof(a) == 4, "");
-  static_assert(sizeof(a) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(a) == 3, ""); // expected-error {{static assertion failed}} \
+ // expected-note {{evaluates to '4'}}
 }
 
 static_assert(1, "");
@@ -40,7 +41,8 @@
   static_assert(1, "");
   _Static_assert(1, "");
   static_assert(sizeof(b) == 4, "");
-  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
+ // expected-note {{evaluates to '4'}}
 }
 
 static_assert(1, "");
@@ -56,7 +58,8 @@
 @interface B () {
   int b;
   static_assert(sizeof(b) == 4, "");
-  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
+ // expected-note {{evalu

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-02 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449226.

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

https://reviews.llvm.org/D130894

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp

Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to '1'}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert-cxx17.cpp
===
--- clang/test/SemaCXX/static-assert-cxx17.cpp
+++ clang/test/SemaCXX/static-assert-cxx17.cpp
@@ -88,7 +88,8 @@
   static_assert(typename T::T(0));
   // expected-error@-1{{static assertion failed due to requirement 'int(0)'}}
   static_assert(sizeof(X) == 0);
-  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X) == 0'}}
+  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X) == 0'}} \
+  // expected-note@-1 {{evaluates to '8'}}
   static_assert((const X *)nullptr);
   // expected-error@-1{{static assertion failed due to requirement '(const X *)nullptr'}}
   static_assert(static_cast *>(nullptr));
@@ -96,7 +97,8 @@
   static_assert((const X[]){} == nullptr);
   // expected-error@-1{{static assertion failed due to requirement '(const X[0]){} == nullptr'}}
   static_assert(sizeof(X().X::~X())>) == 0);
-  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X) == 0'}}
+  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X) == 0'}} \
+  // expected-note@-1 {{evaluates to '8'}}
   static_assert(constexpr_return_false());
   // expected-error@-1{{static assertion failed due to requirement 'constexpr_return_false()'}}
 }
Index: clang/test/Parser/objc-static-assert.mm
===
--- clang/test/Parser/objc-static-assert.mm
+++ clang/test/Parser/objc-static-assert.mm
@@ -26,7 +26,8 @@
 
   static_assert(a, ""); // expected-error {{static assertion expression is not an integral constant expression}}
   static_assert(sizeof(a) == 4, "");
-  static_assert(sizeof(a) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(a) == 3, ""); // expected-error {{static assertion failed}} \
+ // expected-note {{evaluates to '4'}}
 }
 
 static_assert(1, "");
@@ -40,7 +41,8 @@
   static_assert(1, "");
   _Static_assert(1, "");
   static_assert(sizeof(b) == 4, "");
-  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
+ // expected-note {{evaluates to '4'}}
 }
 
 static_assert(1, "");
@@ -56,7 +58,8 @@
 @interface B () {
   int b;
   static_assert(sizeof(b) == 4, "");
-  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
+ // expected-note {{evalu

[PATCH] D130906: [clang] format string checking for conpile-time evaluated str literal

2022-08-02 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

Getting a review usually takes far longer than just a few hours, so don't ping 
too early. I also want an opinion from at least one other reviewer.




Comment at: clang/lib/Sema/SemaChecking.cpp:8505
 
+  // maybe this expression can be evaluated at compile-time
+  // checks if E can be evaluated to some StringLiteral and retry

The comment should be full sentences, start with an upper-case character and 
end in a period:

```
// If this expression can be evaluated at compile-time,
// check if the result is a StringLiteral and retry
```
(just a suggestion)



Comment at: clang/lib/Sema/SemaChecking.cpp:8507
+if (Result.Val.isLValue()) {
+  auto *LVE = Result.Val.getLValueBase().dyn_cast();
+  if (LVE && LVE->getStmtClass() == Stmt::StringLiteralClass) {

tbaeder wrote:
> inclyc wrote:
> > tbaeder wrote:
> > > I think you should be able to unify the two `if` statements.
> > > 
> > > Can you not `dyn_cast_or_null(Result.Val.getLValueBase())` 
> > > here instead of casting to `Expr*` and checking the `StmtClass`?
> > `LValueBase` seems to be a wrapper of a pointer that has its own dyn_cast 
> > method.
> > 
> > I have changed code here like this, but it cannot compile
> > ```
> > auto *MaybeStringLiteral =
> > dyn_cast_or_null(Result.Val.getLValueBase());
> > if (MaybeStringLiteral) {
> >   return checkFormatStringExpr(S, MaybeStringLiteral, Args, APK, 
> > format_idx,
> >firstDataArg, Type, CallType,
> >/*InFunctionCall*/ false, CheckedVarArgs,
> >UncoveredArg, Offset);
> > }
> > ```
> > 
> > ```
> > /llvm-project/llvm/include/llvm/Support/Casting.h:64:53: error: 
> > type 'clang::StringLiteral *' cannot be used prior to '::' because it has 
> > no members
> >   static inline bool doit(const From &Val) { return To::classof(&Val); }
> > ```
> Ah, shame. This ends up calling `dyn_cast` on a `llvm::Pointerunion` as far 
> as I can see, which seems to return `nullptr` in case the cast is 
> unsuccessful anyway, so you could try just exploiting that: 
> https://llvm.org/doxygen/classllvm_1_1PointerUnion.html#a9147352f78d98ee246f25d3300e0aaba
What about this? I.e. usong `StringLiteral*` directly in the `dyn_cast` call?



Comment at: clang/test/Sema/format-strings-scanf.c:236
+  scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char 
*'}} \
+ // expected-note{{format string is defined here}}
   scanf(0 ? "%d %d" : "%d", i); // no warning

inclyc wrote:
> ```
> // long macro
> #include 
> 
> #define SOME_STRANGE_MACRO(a, b) ((0) ? (a) : (b))
> 
> int main() {
>   int *i;
>   scanf(SOME_STRANGE_MACRO("%d", "%d %s"), i);
> }
> ```
> 
> previous:
> ```
> sample.cpp:7:39: warning: more '%' conversions than data arguments 
> [-Wformat-insufficient-args]
>   scanf(SOME_STRANGE_MACRO("%d", "%d %s"), i);
>  ~^
> sample.cpp:3:48: note: expanded from macro 'SOME_STRANGE_MACRO'
> #define SOME_STRANGE_MACRO(a, b) ((0) ? (a) : (b))
>^
> 1 warning generated.
> ```
> 
> now:
> 
> ```
> sample.cpp:7:9: warning: more '%' conversions than data arguments 
> [-Wformat-insufficient-args]
>   scanf(SOME_STRANGE_MACRO("%d", "%d %s"), i);
> ^
> sample.cpp:3:34: note: expanded from macro 'SOME_STRANGE_MACRO'
> #define SOME_STRANGE_MACRO(a, b) ((0) ? (a) : (b))
>  ^
> sample.cpp:7:39: note: format string is defined here
>   scanf(SOME_STRANGE_MACRO("%d", "%d %s"), i);
>  ~^
> sample.cpp:3:48: note: expanded from macro 'SOME_STRANGE_MACRO'
> #define SOME_STRANGE_MACRO(a, b) ((0) ? (a) : (b))
>^
> 1 warning generated.
> ```
> 
> I think it is better to underline the buggy expression, if this sucks maybe 
> we can check if this is constexpr **after** checking conditional operator ` ? 
> :`  or somehow other statement classes ?
I think the output is fine as-is for this patch, but could be improved later. 
Looking at this as a human, I feel as if both of the "expanded from macro" 
notes are redundant. But I guess they can provide useful information in other 
cases.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130906

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


[PATCH] D130906: [clang] format string checking for conpile-time evaluated str literal

2022-08-02 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/Sema/SemaChecking.cpp:8507
+if (Result.Val.isLValue()) {
+  auto *LVE = Result.Val.getLValueBase().dyn_cast();
+  if (LVE && LVE->getStmtClass() == Stmt::StringLiteralClass) {

inclyc wrote:
> tbaeder wrote:
> > tbaeder wrote:
> > > inclyc wrote:
> > > > tbaeder wrote:
> > > > > I think you should be able to unify the two `if` statements.
> > > > > 
> > > > > Can you not 
> > > > > `dyn_cast_or_null(Result.Val.getLValueBase())` here 
> > > > > instead of casting to `Expr*` and checking the `StmtClass`?
> > > > `LValueBase` seems to be a wrapper of a pointer that has its own 
> > > > dyn_cast method.
> > > > 
> > > > I have changed code here like this, but it cannot compile
> > > > ```
> > > > auto *MaybeStringLiteral =
> > > > dyn_cast_or_null(Result.Val.getLValueBase());
> > > > if (MaybeStringLiteral) {
> > > >   return checkFormatStringExpr(S, MaybeStringLiteral, Args, APK, 
> > > > format_idx,
> > > >firstDataArg, Type, CallType,
> > > >/*InFunctionCall*/ false, 
> > > > CheckedVarArgs,
> > > >UncoveredArg, Offset);
> > > > }
> > > > ```
> > > > 
> > > > ```
> > > > /llvm-project/llvm/include/llvm/Support/Casting.h:64:53: 
> > > > error: type 'clang::StringLiteral *' cannot be used prior to '::' 
> > > > because it has no members
> > > >   static inline bool doit(const From &Val) { return To::classof(&Val); }
> > > > ```
> > > Ah, shame. This ends up calling `dyn_cast` on a `llvm::Pointerunion` as 
> > > far as I can see, which seems to return `nullptr` in case the cast is 
> > > unsuccessful anyway, so you could try just exploiting that: 
> > > https://llvm.org/doxygen/classllvm_1_1PointerUnion.html#a9147352f78d98ee246f25d3300e0aaba
> > What about this? I.e. usong `StringLiteral*` directly in the `dyn_cast` 
> > call?
> ```
> FAILED: tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaChecking.cpp.o 
> /usr/lib/llvm/14/bin/clang++ -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GNU_SOURCE 
> -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
> -I/build/tools/clang/lib/Sema -I/clang/lib/Sema 
> -I/clang/include -I/build/tools/clang/include 
> -I/build/include -I/llvm/include -fPIC 
> -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time 
> -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter 
> -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic 
> -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough 
> -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor 
> -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion 
> -Wmisleading-indentation -fdiagnostics-color -fno-common -Woverloaded-virtual 
> -Wno-nested-anon-types -g  -fno-exceptions -fno-rtti -std=c++14 -MD -MT 
> tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaChecking.cpp.o -MF 
> tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaChecking.cpp.o.d -o 
> tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaChecking.cpp.o -c 
> /clang/lib/Sema/SemaChecking.cpp
> In file included from /clang/lib/Sema/SemaChecking.cpp:14:
> In file included from /clang/include/clang/AST/APValue.h:18:
> In file included from /llvm/include/llvm/ADT/APFloat.h:19:
> In file included from /llvm/include/llvm/ADT/ArrayRef.h:15:
> /llvm/include/llvm/ADT/STLExtras.h:199:42: error: implicit 
> instantiation of undefined template 'llvm::FirstIndexOfType clang::StringLiteral *>'
> : std::integral_constant::value> 
> {};
>  ^
> /llvm/include/llvm/ADT/STLExtras.h:199:42: note: in 
> instantiation of template class 'llvm::FirstIndexOfType clang::StringLiteral *, clang::DynamicAllocLValue>' requested here
> /llvm/include/llvm/ADT/STLExtras.h:199:42: note: in 
> instantiation of template class 'llvm::FirstIndexOfType clang::StringLiteral *, clang::TypeInfoLValue, clang::DynamicAllocLValue>' 
> requested here
> /llvm/include/llvm/ADT/STLExtras.h:199:42: note: in 
> instantiation of template class 'llvm::FirstIndexOfType clang::StringLiteral *, const clang::Expr *, clang::TypeInfoLValue, 
> clang::DynamicAllocLValue>' requested here
> /llvm/include/llvm/ADT/PointerUnion.h:230:30: note: in 
> instantiation of template class 'llvm::FirstIndexOfType clang::StringLiteral *, const clang::ValueDecl *, const clang::Expr *, 
> clang::TypeInfoLValue, clang::DynamicAllocLValue>' requested here
> return F.Val.getInt() == FirstIndexOfType::value;
>  ^
> /llvm/include/llvm/ADT/PointerUnion.h:248:27: note: in 
> instantiation of function template specialization 
> 'llvm::CastInfoPointerUnionImpl *, clang::TypeInfoLValue, clang::DynamicAllocLValue>::isPossible clang::StringLiteral *>' requested here
> return Impl::template isPossible(f);
>   ^
> /llvm/include/llvm/Support/Casti

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-02 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

Oh, I noticed that g++ already does this:

  test.cpp:27:21: error: static assertion failed
 27 | static_assert(foo() < 4);
|   ~~^~~
  test.cpp:27:21: note: the comparison reduces to ‘(10 < 4)’


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

https://reviews.llvm.org/D130894

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


[PATCH] D130791: [clang] Short-circuit trivial constexpr array constructors

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG11e52ecf74e9: [clang] Short-circuit trivial constructors 
when evaluating arrays (authored by tbaeder).

Changed prior to commit:
  https://reviews.llvm.org/D130791?vs=449182&id=449585#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130791

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10833,6 +10833,9 @@
 if (FinalSize == 0)
   return true;
 
+bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+Info, E->getExprLoc(), E->getConstructor(),
+E->requiresZeroInitialization());
 LValue ArrayElt = Subobject;
 ArrayElt.addArray(Info, E, CAT);
 // We do the whole initialization in two passes, first for just one 
element,
@@ -10856,19 +10859,26 @@
 for (unsigned I = OldElts; I < N; ++I)
   Value->getArrayInitializedElt(I) = Filler;
 
-  // Initialize the elements.
-  for (unsigned I = OldElts; I < N; ++I) {
-if (!VisitCXXConstructExpr(E, ArrayElt,
-   &Value->getArrayInitializedElt(I),
-   CAT->getElementType()) ||
-!HandleLValueArrayAdjustment(Info, E, ArrayElt,
- CAT->getElementType(), 1))
-  return false;
-// When checking for const initilization any diagnostic is considered
-// an error.
-if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
-!Info.keepEvaluatingAfterFailure())
-  return false;
+  if (HasTrivialConstructor && N == FinalSize) {
+// If we have a trivial constructor, only evaluate it once and copy
+// the result into all the array elements.
+APValue &FirstResult = Value->getArrayInitializedElt(0);
+for (unsigned I = OldElts; I < FinalSize; ++I)
+  Value->getArrayInitializedElt(I) = FirstResult;
+  } else {
+for (unsigned I = OldElts; I < N; ++I) {
+  if (!VisitCXXConstructExpr(E, ArrayElt,
+ &Value->getArrayInitializedElt(I),
+ CAT->getElementType()) ||
+  !HandleLValueArrayAdjustment(Info, E, ArrayElt,
+   CAT->getElementType(), 1))
+return false;
+  // When checking for const initilization any diagnostic is considered
+  // an error.
+  if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
+  !Info.keepEvaluatingAfterFailure())
+return false;
+}
   }
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -54,6 +54,9 @@
   `Issue 56800 `_.
 - Fix `#56772 `_ - invalid
   destructor names were incorrectly accepted on template classes.
+- Improve compile-times with large dynamic array allocations with trivial
+  constructors. This fixes
+  `Issue 56774`_.
 
 Improvements to Clang's diagnostics
 ^^^


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10833,6 +10833,9 @@
 if (FinalSize == 0)
   return true;
 
+bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+Info, E->getExprLoc(), E->getConstructor(),
+E->requiresZeroInitialization());
 LValue ArrayElt = Subobject;
 ArrayElt.addArray(Info, E, CAT);
 // We do the whole initialization in two passes, first for just one element,
@@ -10856,19 +10859,26 @@
 for (unsigned I = OldElts; I < N; ++I)
   Value->getArrayInitializedElt(I) = Filler;
 
-  // Initialize the elements.
-  for (unsigned I = OldElts; I < N; ++I) {
-if (!VisitCXXConstructExpr(E, ArrayElt,
-   &Value->getArrayInitializedElt(I),
-   CAT->getElementType()) ||
-!HandleLValueArrayAdjustment(Info, E, ArrayElt,
- CAT->getElementType(), 1))
-  return false;
-// When checking for const initilization any diagnostic is considered
-// an error.
-if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
-!Info.keepEvaluatingAfterFailure())
-  return false;
+  if (H

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449589.
tbaeder added a comment.

I just took the plunge and made `DiagnoseStaticAssertDetails()` take into 
account all static assertions, regardless of integer literals. It now also 
prints integers, booleans, chars and floats correctly.

For example:

  test.cpp:30:1: error: static assertion failed due to requirement 'inv(true) 
== inv(false)'
  static_assert(inv(true) == inv(false));
  ^ ~~~
  test.cpp:30:15: note: left-hand side of operator '==' evaluates to 'false'
  static_assert(inv(true) == inv(false));
^
  test.cpp:30:28: note: right-hand side of operator '==' evaluates to 'true'
  static_assert(inv(true) == inv(false));
 ^~

the output when both sides are printed is rather clumsy to me, and some things 
are not handled at all (e.g. failed static assertions when the toplevel 
expression is not a `BinaryOpertator`, e.g. `static_assert(!k)` - the user 
doesn't know what value `k` is, which is important in case `k` is of an integer 
type).

But again, this kind of begs people to suggest more and more improvements, but 
I think this is a good enough start :)


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

https://reviews.llvm.org/D130894

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/Lexer/cxx1z-trigraphs.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/Sema/static-assert.c
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaCXX/static-assert.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp
  clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

Index: clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
===
--- clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -184,7 +184,9 @@
 
 namespace Diags {
   struct A { int n, m; };
-  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}}
+  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}} \
+ // expected-note {{evaluates to '1'}} \
+ // expected-note {{evaluates to '2'}}
   template struct X; // expected-note {{in instantiation of template class 'Diags::X<{1, 2}>' requested here}}
 }
 
Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to '1'}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert.cpp
===
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -22,7 +22,8 @@
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static ass

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:16574
+  if (BoolValue) {
+Str.push_back('t');
+Str.push_back('r');

I really hope there's a better way to do this that I just don't know about :)


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

https://reviews.llvm.org/D130894

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


[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449625.
tbaeder added a comment.

Whatever, I had time and you're still asleep, so I updated the output:

  test.cpp:30:1: error: static assertion failed due to requirement 'inv(true) 
== inv(false)'
  static_assert(inv(true) == inv(false));
  ^ ~~~
  test.cpp:30:25: note: expression evaluates to false == true
  static_assert(inv(true) == inv(false));
~~^
  1 error generated.


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

https://reviews.llvm.org/D130894

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/Lexer/cxx1z-trigraphs.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/Sema/static-assert.c
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaCXX/static-assert.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp
  clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

Index: clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
===
--- clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -184,7 +184,8 @@
 
 namespace Diags {
   struct A { int n, m; };
-  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}}
+  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}} \
+ // expected-note {{evaluates to 1 == 2}}
   template struct X; // expected-note {{in instantiation of template class 'Diags::X<{1, 2}>' requested here}}
 }
 
Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to 0}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to 0}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to 1}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert.cpp
===
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -22,7 +22,8 @@
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}}
+static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} \
+ // expected-note {{1 > 1}}
 };
 
 S s1; // expected-note {{in instantiation of template class 'S' requested here}}
@@ -215,3 +216,32 @@
 static_assert(constexprNotBool, "message"); // expected-error {{value of type 'const NotBool' is not contextually convertible to 'bool'}}
 
 static_assert(1 , "") // expected-error {{expected ';' after 'static_assert'}}
+
+
+namespace Diagnostics {
+  /// No notes for literals.
+  static_assert(false, ""); // expected-error {{failed}}
+  stat

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449637.
tbaeder added a comment.

Also print `nullptr` expressions.


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

https://reviews.llvm.org/D130894

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/Lexer/cxx1z-trigraphs.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/Sema/static-assert.c
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaCXX/static-assert.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp
  clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

Index: clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
===
--- clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -184,7 +184,8 @@
 
 namespace Diags {
   struct A { int n, m; };
-  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}}
+  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}} \
+ // expected-note {{evaluates to 1 == 2}}
   template struct X; // expected-note {{in instantiation of template class 'Diags::X<{1, 2}>' requested here}}
 }
 
Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to 0}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to 0}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to 1}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert.cpp
===
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -22,7 +22,8 @@
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}}
+static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} \
+ // expected-note {{1 > 1}}
 };
 
 S s1; // expected-note {{in instantiation of template class 'S' requested here}}
@@ -215,3 +216,32 @@
 static_assert(constexprNotBool, "message"); // expected-error {{value of type 'const NotBool' is not contextually convertible to 'bool'}}
 
 static_assert(1 , "") // expected-error {{expected ';' after 'static_assert'}}
+
+
+namespace Diagnostics {
+  /// No notes for literals.
+  static_assert(false, ""); // expected-error {{failed}}
+  static_assert(1.0 > 2.0, ""); // expected-error {{failed}}
+  static_assert('c' == 'd', ""); // expected-error {{failed}}
+  static_assert(1 == 2, ""); // expected-error {{failed}}
+
+  /// Simple things are ignored.
+  static_assert(1 == (-(1)), ""); //expected-error {{failed}}
+
+  /// Chars are printed as chars.
+  constexpr char getChar() {
+return 'c';
+  }
+  static_asse

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449639.

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

https://reviews.llvm.org/D130894

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/Lexer/cxx1z-trigraphs.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/Sema/static-assert.c
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaCXX/static-assert.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp
  clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

Index: clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
===
--- clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -184,7 +184,8 @@
 
 namespace Diags {
   struct A { int n, m; };
-  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}}
+  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}} \
+ // expected-note {{evaluates to 1 == 2}}
   template struct X; // expected-note {{in instantiation of template class 'Diags::X<{1, 2}>' requested here}}
 }
 
Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to 0}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to 0}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to 1}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert.cpp
===
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -22,7 +22,8 @@
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}}
+static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} \
+ // expected-note {{1 > 1}}
 };
 
 S s1; // expected-note {{in instantiation of template class 'S' requested here}}
@@ -215,3 +216,32 @@
 static_assert(constexprNotBool, "message"); // expected-error {{value of type 'const NotBool' is not contextually convertible to 'bool'}}
 
 static_assert(1 , "") // expected-error {{expected ';' after 'static_assert'}}
+
+
+namespace Diagnostics {
+  /// No notes for literals.
+  static_assert(false, ""); // expected-error {{failed}}
+  static_assert(1.0 > 2.0, ""); // expected-error {{failed}}
+  static_assert('c' == 'd', ""); // expected-error {{failed}}
+  static_assert(1 == 2, ""); // expected-error {{failed}}
+
+  /// Simple things are ignored.
+  static_assert(1 == (-(1)), ""); //expected-error {{failed}}
+
+  /// Chars are printed as chars.
+  constexpr char getChar() {
+return 'c';
+  }
+  static_assert(getChar() == 'a', ""); // expected-error {{failed}} \
+   

[PATCH] D131070: [clang][sema] Fix collectConjunctionTerms()

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added a reviewer: aaron.ballman.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Consider:

A == 5 && A != 5

IfA is 5, the old collectConjunctionTerms() would call itself again for
the LHS (which it ignores), then  the RHS (which it also ignores) and
then just return without ever adding anything to the Terms array.

For example, there's a test case in `clang/test/SemaCXX/recovery-expr-type.cpp`:

  namespace test13 {
  enum Circular { // expected-note {{not complete until the closing 
'}'}}
Circular_A = Circular(1), // expected-error {{'Circular' is an incomplete 
type}}
  };
  // Enumerators can be evaluated (they evaluate as zero, but we don't care).
  static_assert(Circular_A == 0 && Circular_A != 0, ""); // expected-error 
{{static assertion failed}}
  }

which currently prints:

  test2.cpp:6:1: error: static assertion failed due to requirement 'Circular_A 
== 0 && Circular_A != 0':
  static_assert(Circular_A == 0 && Circular_A != 0, ""); // expected-error 
{{static assertion failed}}
  ^ ~~
  2 errors generated.

(other diagnostics omitted)

but after this change prints:

  test2.cpp:6:1: error: static assertion failed due to requirement 'Circular_A 
!= 0':
  static_assert(Circular_A == 0 && Circular_A != 0, ""); // expected-error 
{{static assertion failed}}
  ^~~~
  2 errors generated.

The patch depends on https://reviews.llvm.org/D130894 because of the note it 
adds, but that's not necessary. It's just easier because they are both in my 
local tree.

I wanted to add Douglas Gregor as reviewer as well but seems like he isn't 
around anymore.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131070

Files:
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/SemaCXX/recovery-expr-type.cpp


Index: clang/test/SemaCXX/recovery-expr-type.cpp
===
--- clang/test/SemaCXX/recovery-expr-type.cpp
+++ clang/test/SemaCXX/recovery-expr-type.cpp
@@ -149,7 +149,8 @@
   Circular_A = Circular(1), // expected-error {{'Circular' is an incomplete 
type}}
 };
 // Enumerators can be evaluated (they evaluate as zero, but we don't care).
-static_assert(Circular_A == 0 && Circular_A != 0, ""); // expected-error 
{{static assertion failed}}
+static_assert(Circular_A == 0 && Circular_A != 0, ""); // expected-error 
{{static assertion failed}} \
+   // expected-note 
{{evaluates to 0}}
 }
 
 namespace test14 {
Index: clang/lib/Sema/SemaTemplate.cpp
===
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3585,9 +3585,8 @@
 if (BinOp->getOpcode() == BO_LAnd) {
   collectConjunctionTerms(BinOp->getLHS(), Terms);
   collectConjunctionTerms(BinOp->getRHS(), Terms);
+  return;
 }
-
-return;
   }
 
   Terms.push_back(Clause);


Index: clang/test/SemaCXX/recovery-expr-type.cpp
===
--- clang/test/SemaCXX/recovery-expr-type.cpp
+++ clang/test/SemaCXX/recovery-expr-type.cpp
@@ -149,7 +149,8 @@
   Circular_A = Circular(1), // expected-error {{'Circular' is an incomplete type}}
 };
 // Enumerators can be evaluated (they evaluate as zero, but we don't care).
-static_assert(Circular_A == 0 && Circular_A != 0, ""); // expected-error {{static assertion failed}}
+static_assert(Circular_A == 0 && Circular_A != 0, ""); // expected-error {{static assertion failed}} \
+   // expected-note {{evaluates to 0}}
 }
 
 namespace test14 {
Index: clang/lib/Sema/SemaTemplate.cpp
===
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3585,9 +3585,8 @@
 if (BinOp->getOpcode() == BO_LAnd) {
   collectConjunctionTerms(BinOp->getLHS(), Terms);
   collectConjunctionTerms(BinOp->getRHS(), Terms);
+  return;
 }
-
-return;
   }
 
   Terms.push_back(Clause);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

FWIW, complex numbers are already covered it seems:

  test.cpp:35:1: error: static assertion failed due to requirement '__real c == 
__imag c'
  static_assert(__real c == __imag c);
  ^ 
  test.cpp:35:24: note: expression evaluates to 5 == 6
  static_assert(__real c == __imag c);
~^~~
  1 error generated.


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

https://reviews.llvm.org/D130894

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


[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449669.
tbaeder added a comment.

Ignore what I said, they are supported now though.


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

https://reviews.llvm.org/D130894

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/Lexer/cxx1z-trigraphs.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/Sema/static-assert.c
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaCXX/static-assert.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp
  clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

Index: clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
===
--- clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -184,7 +184,8 @@
 
 namespace Diags {
   struct A { int n, m; };
-  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}}
+  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}} \
+ // expected-note {{evaluates to 1 == 2}}
   template struct X; // expected-note {{in instantiation of template class 'Diags::X<{1, 2}>' requested here}}
 }
 
Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to 0}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to 0}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to 1}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert.cpp
===
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -22,7 +22,8 @@
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}}
+static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} \
+ // expected-note {{1 > 1}}
 };
 
 S s1; // expected-note {{in instantiation of template class 'S' requested here}}
@@ -215,3 +216,40 @@
 static_assert(constexprNotBool, "message"); // expected-error {{value of type 'const NotBool' is not contextually convertible to 'bool'}}
 
 static_assert(1 , "") // expected-error {{expected ';' after 'static_assert'}}
+
+
+namespace Diagnostics {
+  /// No notes for literals.
+  static_assert(false, ""); // expected-error {{failed}}
+  static_assert(1.0 > 2.0, ""); // expected-error {{failed}}
+  static_assert('c' == 'd', ""); // expected-error {{failed}}
+  static_assert(1 == 2, ""); // expected-error {{failed}}
+
+  /// Simple things are ignored.
+  static_assert(1 == (-(1)), ""); //expected-error {{failed}}
+
+  /// Chars are printed as chars.
+  constexpr char getChar() {
+return 'c';
+ 

[PATCH] D131070: [clang][sema] Fix collectConjunctionTerms()

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

That's just because of the note that  https://reviews.llvm.org/D130894 adds, 
which the patch expects.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D131070

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


[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder marked 4 inline comments as done.
tbaeder added a comment.

> +1 to the suggestion to use quotes for a bit of visual distinction between 
> the diagnostic message and the code embedded within it.

One problem is that both the integer value `0` and the character constant `'0'` 
are printed as `'0'` (same for all other single-digit numbers). gcc's output 
doesn't have that problem because it prints chars as integers, but  I don't 
really like that.


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

https://reviews.llvm.org/D130894

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


[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449874.

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

https://reviews.llvm.org/D130894

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/Lexer/cxx1z-trigraphs.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/Sema/static-assert.c
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/recovery-expr-type.cpp
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaCXX/static-assert.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp
  clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

Index: clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
===
--- clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -184,7 +184,8 @@
 
 namespace Diags {
   struct A { int n, m; };
-  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}}
+  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}} \
+ // expected-note {{evaluates to '1 == 2'}}
   template struct X; // expected-note {{in instantiation of template class 'Diags::X<{1, 2}>' requested here}}
 }
 
Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to '1'}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert.cpp
===
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -22,7 +22,8 @@
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}}
+static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} \
+ // expected-note {{1 > 1}}
 };
 
 S s1; // expected-note {{in instantiation of template class 'S' requested here}}
@@ -215,3 +216,40 @@
 static_assert(constexprNotBool, "message"); // expected-error {{value of type 'const NotBool' is not contextually convertible to 'bool'}}
 
 static_assert(1 , "") // expected-error {{expected ';' after 'static_assert'}}
+
+
+namespace Diagnostics {
+  /// No notes for literals.
+  static_assert(false, ""); // expected-error {{failed}}
+  static_assert(1.0 > 2.0, ""); // expected-error {{failed}}
+  static_assert('c' == 'd', ""); // expected-error {{failed}}
+  static_assert(1 == 2, ""); // expected-error {{failed}}
+
+  /// Simple things are ignored.
+  static_assert(1 == (-(1)), ""); //expected-error {{failed}}
+
+  /// Chars are printed as chars.
+  constexpr char getChar() {
+return 'c';
+  }
+  static_assert(getCha

[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449885.

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

https://reviews.llvm.org/D130894

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/Lexer/cxx1z-trigraphs.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/Sema/static-assert.c
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/recovery-expr-type.cpp
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaCXX/static-assert.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp
  clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

Index: clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
===
--- clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -184,7 +184,8 @@
 
 namespace Diags {
   struct A { int n, m; };
-  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}}
+  template struct X { static_assert(a.n == a.m); }; // expected-error {{static assertion failed due to requirement 'Diags::A{1, 2}.n == Diags::A{1, 2}.m'}} \
+ // expected-note {{evaluates to '1 == 2'}}
   template struct X; // expected-note {{in instantiation of template class 'Diags::X<{1, 2}>' requested here}}
 }
 
Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait::specialization == 0);
-  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait::specialization == 1); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
+  static_assert(trait::specialization == 2); // FIXME expected-error {{failed}} \
+// expected-note {{evaluates to '0'}}
   static_assert(trait::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template void f() {
-static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}}
+static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \
+   // expected-note {{evaluates to '1'}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert.cpp
===
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -22,7 +22,8 @@
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}}
+static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} \
+ // expected-note {{1 > 1}}
 };
 
 S s1; // expected-note {{in instantiation of template class 'S' requested here}}
@@ -215,3 +216,40 @@
 static_assert(constexprNotBool, "message"); // expected-error {{value of type 'const NotBool' is not contextually convertible to 'bool'}}
 
 static_assert(1 , "") // expected-error {{expected ';' after 'static_assert'}}
+
+
+namespace Diagnostics {
+  /// No notes for literals.
+  static_assert(false, ""); // expected-error {{failed}}
+  static_assert(1.0 > 2.0, ""); // expected-error {{failed}}
+  static_assert('c' == 'd', ""); // expected-error {{failed}}
+  static_assert(1 == 2, ""); // expected-error {{failed}}
+
+  /// Simple things are ignored.
+  static_assert(1 == (-(1)), ""); //expected-error {{failed}}
+
+  /// Chars are printed as chars.
+  constexpr char getChar() {
+return 'c';
+  }
+  static_assert(getCha

[PATCH] D128248: [clang] Avoid an assertion in APValue::hasArrayFiller()

2022-08-04 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder abandoned this revision.
tbaeder added a comment.

Abandoning as per the discussion in 
https://discourse.llvm.org/t/apvalue-lifetime-problem-when-evaluating-constant-expressions/64002/5.
 This patch just hides a problem.


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

https://reviews.llvm.org/D128248

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


[PATCH] D131155: [clang] Expand array expressions if the filler expression's filler is element dependent

2022-08-04 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This is about the problem described in 
https://discourse.llvm.org/t/apvalue-lifetime-problem-when-evaluating-constant-expressions/64002/5

The (old) condition in this if statement is meant to handle initializers that 
depend on (other) array elements. In this case, the array needs to be expanded 
before the array filler is evaluated:

  if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(FillerExpr))
NumEltsToInit = NumElts;

in the test case described on Discourse (which is attached in the patch), 
`MaybeElementDependentArrayFiller()` returns `false` for the outer array but 
true for the inner array. Since every `InitListExpr` can have an array filler, 
I believe the function should take that into account.

This fixes https://github.com/llvm/llvm-project/issues/56016


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131155

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constexpr-array-init.cpp


Index: clang/test/SemaCXX/constexpr-array-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/constexpr-array-init.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+struct Foo {
+  int a;
+  constexpr Foo()
+  : a(get_int()) {
+  }
+
+  constexpr int get_int() const {
+return 5;
+  }
+};
+
+static constexpr Foo bar[2][1] = {
+{{}},
+};
+static_assert(bar[0][0].a == 5);
+static_assert(bar[1][0].a == 5);
+
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10695,6 +10695,11 @@
   if (MaybeElementDependentArrayFiller(ILE->getInit(I)))
 return true;
 }
+
+if (ILE->hasArrayFiller() &&
+MaybeElementDependentArrayFiller(ILE->getArrayFiller()))
+  return true;
+
 return false;
   }
   return true;


Index: clang/test/SemaCXX/constexpr-array-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/constexpr-array-init.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+struct Foo {
+  int a;
+  constexpr Foo()
+  : a(get_int()) {
+  }
+
+  constexpr int get_int() const {
+return 5;
+  }
+};
+
+static constexpr Foo bar[2][1] = {
+{{}},
+};
+static_assert(bar[0][0].a == 5);
+static_assert(bar[1][0].a == 5);
+
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -10695,6 +10695,11 @@
   if (MaybeElementDependentArrayFiller(ILE->getInit(I)))
 return true;
 }
+
+if (ILE->hasArrayFiller() &&
+MaybeElementDependentArrayFiller(ILE->getArrayFiller()))
+  return true;
+
 return false;
   }
   return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D131070: [clang][sema] Fix collectConjunctionTerms()

2022-08-04 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 449930.

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

https://reviews.llvm.org/D131070

Files:
  clang/lib/Sema/SemaTemplate.cpp


Index: clang/lib/Sema/SemaTemplate.cpp
===
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3585,9 +3585,8 @@
 if (BinOp->getOpcode() == BO_LAnd) {
   collectConjunctionTerms(BinOp->getLHS(), Terms);
   collectConjunctionTerms(BinOp->getRHS(), Terms);
+  return;
 }
-
-return;
   }
 
   Terms.push_back(Clause);


Index: clang/lib/Sema/SemaTemplate.cpp
===
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3585,9 +3585,8 @@
 if (BinOp->getOpcode() == BO_LAnd) {
   collectConjunctionTerms(BinOp->getLHS(), Terms);
   collectConjunctionTerms(BinOp->getRHS(), Terms);
+  return;
 }
-
-return;
   }
 
   Terms.push_back(Clause);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130894: [clang] Print more information about failed static assertions

2022-08-04 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

IMO it's clear enough...

  test.cpp:24:1: error: static assertion failed due to requirement 'c != c'
  static_assert(c != c);
  ^ ~~
  test.cpp:24:17: note: expression evaluates to 'a != a'
  static_assert(c != c);
~~^~~~
  test.cpp:25:1: error: static assertion failed due to requirement 'c < 'a''
  static_assert(c < 'a');
  ^ ~~~
  test.cpp:25:15: note: left-hand side of operator '<' evaluates to 'a'
  static_assert(c < 'a');
^
  2 errors generated.

Printing the first note as ''a' != 'a'' doesn't make it clearer. But for

  test.cpp:24:1: error: static assertion failed due to requirement 'c != c'
  static_assert(c != c);
  ^ ~~
  test.cpp:24:17: note: expression evaluates to '0 != 0'
  static_assert(c != c);
~~^~~~
  test.cpp:25:1: error: static assertion failed due to requirement 'c > 'a''
  static_assert(c > 'a');
  ^ ~~~
  test.cpp:25:15: note: left-hand side of operator '>' evaluates to '0'
  static_assert(c > 'a');
^

where `c` is a char variable, the output looks kind of weird. "0 != 0" looks 
like we're comparing two integers.

We might also go the g++ route and use `evaluates to ('0' != '0')` for the full 
expression, but that looks weird for just one side: `evaluates to (6)`. But we 
could also always print the full expression so we only have one case.


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

https://reviews.llvm.org/D130894

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


  1   2   3   4   5   6   7   8   9   10   >