[PATCH] D50421: [libcxx] [test] Remove assertion that includes and .

2018-08-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

This looks fine to me.


https://reviews.llvm.org/D50421



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


[PATCH] D50549: [libcxx] [test] Repair thread unsafety in thread tests

2018-08-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

We should add some TSAN folks to this review, since I think these are also TSAN 
false negatives; perhaps correctly, perhaps not.


https://reviews.llvm.org/D50549



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


[PATCH] D50549: [libcxx] [test] Repair thread unsafety in thread tests

2018-08-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

I was hoping my comment would summon them magically. I'll figure it out shortly.


https://reviews.llvm.org/D50549



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


[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF created this revision.
EricWF added reviewers: rsmith, rjmccall, majnemer, vsapsai.

The Itanium ABI requires that the type info for pointer-to-incomplete types to 
have internal linkage, so that it doesn't interfere with the type info once 
completed.  Currently it also marks the type info name as internal as well. 
However, this causes a bug with the STL implementations, which use the type 
info name pointer to perform ordering and hashing of type infos.
For example:

  // header.h
  struct T;
  extern std::type_info const& Info;
  
  // tu_one.cpp
  #include "header.h"
  std::type_info const& Info = typeid(T*);
  
  // tu_two.cpp
  #include "header.h"
  struct T {};
  int main() {
auto &TI1 = Info;
auto &TI2 = typeid(T*);
assert(TI1 == TI2); // Fails
assert(TI1.hash_code() == TI2.hash_code()); // Fails
  }

This patch fixes the STL bug by emitting the type info name as linkonce_odr 
when the type-info is for a pointer-to-incomplete type.

Note that libc++ could fix this without a compiler change, but the quality of 
fix would be poor. The library would either have to:

(A) Always perform strcmp/string hashes.
(B) Determine if we have a pointer-to-incomplete type, and only do strcmp then. 
This would require an ABI break for libc++.


https://reviews.llvm.org/D46665

Files:
  lib/CodeGen/ItaniumCXXABI.cpp
  test/CodeGenCXX/rtti-linkage.cpp

Index: test/CodeGenCXX/rtti-linkage.cpp
===
--- test/CodeGenCXX/rtti-linkage.cpp
+++ test/CodeGenCXX/rtti-linkage.cpp
@@ -3,27 +3,27 @@
 
 #include 
 
-// CHECK-BOTH: _ZTSP1C = internal constant
+// CHECK-BOTH: _ZTSP1C = linkonce_odr constant
 // CHECK-BOTH: _ZTS1C = internal constant
 // CHECK-BOTH: _ZTI1C = internal constant
 // CHECK-BOTH: _ZTIP1C = internal constant
-// CHECK-BOTH: _ZTSPP1C = internal constant
+// CHECK-BOTH: _ZTSPP1C = linkonce_odr constant
 // CHECK-BOTH: _ZTIPP1C = internal constant
-// CHECK-BOTH: _ZTSM1Ci = internal constant
+// CHECK-BOTH: _ZTSM1Ci = linkonce_odr constant
 // CHECK-BOTH: _ZTIM1Ci = internal constant
-// CHECK-BOTH: _ZTSPM1Ci = internal constant
+// CHECK-BOTH: _ZTSPM1Ci = linkonce_odr constant
 // CHECK-BOTH: _ZTIPM1Ci = internal constant
-// CHECK-BOTH: _ZTSM1CS_ = internal constant
+// CHECK-BOTH: _ZTSM1CS_ = linkonce_odr constant
 // CHECK-BOTH: _ZTIM1CS_ = internal constant
-// CHECK-BOTH: _ZTSM1CPS_ = internal constant
+// CHECK-BOTH: _ZTSM1CPS_ = linkonce_odr constant
 // CHECK-BOTH: _ZTIM1CPS_ = internal constant
-// CHECK-BOTH: _ZTSM1A1C = internal constant
+// CHECK-BOTH: _ZTSM1A1C = linkonce_odr constant
 // CHECK: _ZTS1A = linkonce_odr constant
 // CHECK-WITH-HIDDEN: _ZTS1A = linkonce_odr hidden constant
 // CHECK: _ZTI1A = linkonce_odr constant
 // CHECK-WITH-HIDDEN: _ZTI1A = linkonce_odr hidden constant
 // CHECK-BOTH: _ZTIM1A1C = internal constant
-// CHECK-BOTH: _ZTSM1AP1C = internal constant
+// CHECK-BOTH: _ZTSM1AP1C = linkonce_odr constant
 // CHECK-BOTH: _ZTIM1AP1C = internal constant
 
 // CHECK-WITH-HIDDEN: _ZTSFN12_GLOBAL__N_11DEvE = internal constant
Index: lib/CodeGen/ItaniumCXXABI.cpp
===
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -3008,8 +3008,9 @@
 
 /// \brief Return the linkage that the type info and type info name constants
 /// should have for the given type.
-static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
- QualType Ty) {
+static std::pair
+getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
   // Itanium C++ ABI 2.9.5p7:
   //   In addition, it and all of the intermediate abi::__pointer_type_info
   //   structs in the chain down to the abi::__class_type_info for the
@@ -3019,9 +3020,22 @@
   //   generated for the incomplete type that will not resolve to the final
   //   complete class RTTI (because the latter need not exist), possibly by
   //   making it a local static object.
-  if (ContainsIncompleteClassType(Ty))
-return llvm::GlobalValue::InternalLinkage;
+  if (ContainsIncompleteClassType(Ty)) {
+// Itanium C++ ABI 2.9.3:
+//  The name() member function returns the address of an NTBS, unique to the
+//  type, ...
+//
+// This means we should emit the type info name visibly, so that the type
+// info objects for the complete and incomplete types share the same string.
+// See llvm.org/PR37398
+if (Ty->isPointerType() || Ty->isMemberPointerType())
+  return {llvm::GlobalValue::InternalLinkage,
+  llvm::GlobalValue::LinkOnceODRLinkage};
+return {llvm::GlobalValue::InternalLinkage,
+llvm::GlobalValue::InternalLinkage};
+  }
 
+  llvm::GlobalValue::LinkageTypes LinkageForType = [&]() {
 switch (Ty->getLinkage()) {
 case NoLinkage:
 case InternalLinkage:
@@ -3046,18 +3060,18 @@
   ShouldUseExternalRTTIDescriptor(CGM, Ty))
   

[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146034.
EricWF added a comment.

- Correct copy-paste error.


https://reviews.llvm.org/D46665

Files:
  lib/CodeGen/ItaniumCXXABI.cpp
  test/CodeGenCXX/rtti-linkage.cpp

Index: test/CodeGenCXX/rtti-linkage.cpp
===
--- test/CodeGenCXX/rtti-linkage.cpp
+++ test/CodeGenCXX/rtti-linkage.cpp
@@ -3,27 +3,27 @@
 
 #include 
 
-// CHECK-BOTH: _ZTSP1C = internal constant
+// CHECK-BOTH: _ZTSP1C = linkonce_odr constant
 // CHECK-BOTH: _ZTS1C = internal constant
 // CHECK-BOTH: _ZTI1C = internal constant
 // CHECK-BOTH: _ZTIP1C = internal constant
-// CHECK-BOTH: _ZTSPP1C = internal constant
+// CHECK-BOTH: _ZTSPP1C = linkonce_odr constant
 // CHECK-BOTH: _ZTIPP1C = internal constant
-// CHECK-BOTH: _ZTSM1Ci = internal constant
+// CHECK-BOTH: _ZTSM1Ci = linkonce_odr constant
 // CHECK-BOTH: _ZTIM1Ci = internal constant
-// CHECK-BOTH: _ZTSPM1Ci = internal constant
+// CHECK-BOTH: _ZTSPM1Ci = linkonce_odr constant
 // CHECK-BOTH: _ZTIPM1Ci = internal constant
-// CHECK-BOTH: _ZTSM1CS_ = internal constant
+// CHECK-BOTH: _ZTSM1CS_ = linkonce_odr constant
 // CHECK-BOTH: _ZTIM1CS_ = internal constant
-// CHECK-BOTH: _ZTSM1CPS_ = internal constant
+// CHECK-BOTH: _ZTSM1CPS_ = linkonce_odr constant
 // CHECK-BOTH: _ZTIM1CPS_ = internal constant
-// CHECK-BOTH: _ZTSM1A1C = internal constant
+// CHECK-BOTH: _ZTSM1A1C = linkonce_odr constant
 // CHECK: _ZTS1A = linkonce_odr constant
 // CHECK-WITH-HIDDEN: _ZTS1A = linkonce_odr hidden constant
 // CHECK: _ZTI1A = linkonce_odr constant
 // CHECK-WITH-HIDDEN: _ZTI1A = linkonce_odr hidden constant
 // CHECK-BOTH: _ZTIM1A1C = internal constant
-// CHECK-BOTH: _ZTSM1AP1C = internal constant
+// CHECK-BOTH: _ZTSM1AP1C = linkonce_odr constant
 // CHECK-BOTH: _ZTIM1AP1C = internal constant
 
 // CHECK-WITH-HIDDEN: _ZTSFN12_GLOBAL__N_11DEvE = internal constant
Index: lib/CodeGen/ItaniumCXXABI.cpp
===
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -3008,8 +3008,9 @@
 
 /// \brief Return the linkage that the type info and type info name constants
 /// should have for the given type.
-static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
- QualType Ty) {
+static std::pair
+getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
   // Itanium C++ ABI 2.9.5p7:
   //   In addition, it and all of the intermediate abi::__pointer_type_info
   //   structs in the chain down to the abi::__class_type_info for the
@@ -3019,9 +3020,22 @@
   //   generated for the incomplete type that will not resolve to the final
   //   complete class RTTI (because the latter need not exist), possibly by
   //   making it a local static object.
-  if (ContainsIncompleteClassType(Ty))
-return llvm::GlobalValue::InternalLinkage;
+  if (ContainsIncompleteClassType(Ty)) {
+// Itanium C++ ABI 2.9.3:
+//  The name() member function returns the address of an NTBS, unique to the
+//  type, ...
+//
+// This means we should emit the type info name visibly, so that the type
+// info objects for the complete and incomplete types share the same string.
+// See llvm.org/PR37398
+if (Ty->isPointerType() || Ty->isMemberPointerType())
+  return {llvm::GlobalValue::InternalLinkage,
+  llvm::GlobalValue::LinkOnceODRLinkage};
+return {llvm::GlobalValue::InternalLinkage,
+llvm::GlobalValue::InternalLinkage};
+  }
 
+  llvm::GlobalValue::LinkageTypes LinkageForType = [&]() {
 switch (Ty->getLinkage()) {
 case NoLinkage:
 case InternalLinkage:
@@ -3046,18 +3060,18 @@
   ShouldUseExternalRTTIDescriptor(CGM, Ty))
 return llvm::GlobalValue::ExternalLinkage;
 // MinGW always uses LinkOnceODRLinkage for type info.
-  if (RD->isDynamicClass() &&
-  !CGM.getContext()
+if (RD->isDynamicClass() && !CGM.getContext()
  .getTargetInfo()
  .getTriple()
  .isWindowsGNUEnvironment())
   return CGM.getVTableLinkage(RD);
   }
 
   return llvm::GlobalValue::LinkOnceODRLinkage;
 }
-
 llvm_unreachable("Invalid linkage!");
+  }();
+  return {LinkageForType, LinkageForType};
 }
 
 llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force,
@@ -3084,23 +3098,25 @@
 return GetAddrOfExternalRTTIDescriptor(Ty);
 
   // Emit the standard library with external linkage.
-  llvm::GlobalVariable::LinkageTypes Linkage;
+  llvm::GlobalVariable::LinkageTypes TInfoLinkage, NameLinkage;
   if (IsStdLib)
-Linkage = llvm::GlobalValue::ExternalLinkage;
-  else
-Linkage = getTypeInfoLinkage(CGM, Ty);
-
+TInfoLinkage = NameLinkage = llvm::GlobalValue::ExternalLinkage;
+  else {
+auto TInfoNameLinkage 

[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked an inline comment as done.
EricWF added a comment.

@rsmith What should the visibility of the type name be in cases where the type 
info is hidden?




Comment at: lib/CodeGen/ItaniumCXXABI.cpp:3033
+  return {llvm::GlobalValue::InternalLinkage,
+  llvm::GlobalValue::LinkOnceODRLinkage};
+return {llvm::GlobalValue::InternalLinkage,

rsmith wrote:
> Shouldn't this be based on the type's linkage? Eg:
> 
> ```
> namespace { struct Incomplete; }
> auto x = typeid(Incomplete*);
> ```
> 
> should have an `internal` type info name, not a `linkonce_odr` name. I think 
> we should compute the linkage per the code below and then demote the type's 
> linkage to internal in the incomplete-class case.
That sounds correct to me.



Comment at: lib/CodeGen/ItaniumCXXABI.cpp:3034-3035
+  llvm::GlobalValue::LinkOnceODRLinkage};
+return {llvm::GlobalValue::InternalLinkage,
+llvm::GlobalValue::InternalLinkage};
+  }

rsmith wrote:
> Should we promote the type info name in this case too? (We get here for the 
> incomplete-class type info we generate as a detail of the pointer type info, 
> but the names of such types are accessible via the  interface, so 
> it seems reasonable to apply the same global-uniqueness to them too.)
Hmm. I think it seems reasonable.

I don't think there exists a case where a user can perform `type_info` equality 
or hashing on an incomplete class type,  so in terms of solving the libc++ bug 
I think it's unneeded. (which is why I omitted it).

I also don't see exactly what part of `cxxabi.h` might expose the `type_info` 
to users in a way where type name pointer equality is important to the user.

What would you rather?



https://reviews.llvm.org/D46665



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


[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146053.
EricWF marked an inline comment as done.
EricWF added a comment.

Address @rsmith's inline comments.

- Calculate the linkage for the type name using the linkage for the type.
- Promote the type name visibility for the incomplete class types as well as 
for pointer and member pointers.


https://reviews.llvm.org/D46665

Files:
  lib/CodeGen/ItaniumCXXABI.cpp
  test/CodeGenCXX/rtti-linkage.cpp

Index: test/CodeGenCXX/rtti-linkage.cpp
===
--- test/CodeGenCXX/rtti-linkage.cpp
+++ test/CodeGenCXX/rtti-linkage.cpp
@@ -1,29 +1,31 @@
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-BOTH
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | FileCheck -check-prefix=CHECK-WITH-HIDDEN -check-prefix=CHECK-BOTH %s
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | \
+// RUN:FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-BOTH \
+// RUN:   -DLINKONCE_VIS_CONSTANT='linkonce_odr constant'
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | \
+// RUN:FileCheck %s -check-prefix=CHECK-WITH-HIDDEN -check-prefix=CHECK-BOTH \
+// RUN:   -DLINKONCE_VIS_CONSTANT='linkonce_odr hidden constant'
 
 #include 
 
-// CHECK-BOTH: _ZTSP1C = internal constant
-// CHECK-BOTH: _ZTS1C = internal constant
+// CHECK-BOTH: _ZTSP1C = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTS1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTI1C = internal constant
 // CHECK-BOTH: _ZTIP1C = internal constant
-// CHECK-BOTH: _ZTSPP1C = internal constant
+// CHECK-BOTH: _ZTSPP1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIPP1C = internal constant
-// CHECK-BOTH: _ZTSM1Ci = internal constant
+// CHECK-BOTH: _ZTSM1Ci = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1Ci = internal constant
-// CHECK-BOTH: _ZTSPM1Ci = internal constant
+// CHECK-BOTH: _ZTSPM1Ci = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIPM1Ci = internal constant
-// CHECK-BOTH: _ZTSM1CS_ = internal constant
+// CHECK-BOTH: _ZTSM1CS_ = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1CS_ = internal constant
-// CHECK-BOTH: _ZTSM1CPS_ = internal constant
+// CHECK-BOTH: _ZTSM1CPS_ = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1CPS_ = internal constant
-// CHECK-BOTH: _ZTSM1A1C = internal constant
-// CHECK: _ZTS1A = linkonce_odr constant
-// CHECK-WITH-HIDDEN: _ZTS1A = linkonce_odr hidden constant
-// CHECK: _ZTI1A = linkonce_odr constant
-// CHECK-WITH-HIDDEN: _ZTI1A = linkonce_odr hidden constant
+// CHECK-BOTH: _ZTSM1A1C = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTS1A = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTI1A = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1A1C = internal constant
-// CHECK-BOTH: _ZTSM1AP1C = internal constant
+// CHECK-BOTH: _ZTSM1AP1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1AP1C = internal constant
 
 // CHECK-WITH-HIDDEN: _ZTSFN12_GLOBAL__N_11DEvE = internal constant
@@ -52,6 +54,12 @@
 // CHECK: _ZTSFvvE = linkonce_odr constant
 // CHECK: _ZTIFvvE = linkonce_odr constant
 // CHECK: _ZTIPFvvE = linkonce_odr constant
+// CHECK: _ZTSPN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTSN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTIN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTIPN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTSMN12_GLOBAL__N_12DIEFvvE = internal constant
+// CHECK: _ZTIMN12_GLOBAL__N_12DIEFvvE = internal constant
 // CHECK: _ZTSN12_GLOBAL__N_11EE = internal constant
 // CHECK: _ZTIN12_GLOBAL__N_11EE = internal constant
 // CHECK: _ZTSA10_i = linkonce_odr constant
@@ -99,9 +107,10 @@
 }
 
 namespace {
-  // D is inside an anonymous namespace, so all type information related to D should have
-  // internal linkage.
+// D and DI are inside an anonymous namespace, so all type information related
+// to both should have internal linkage.
 struct D {};
+struct DI;
 
 // E is also inside an anonymous namespace.
 enum E {};
@@ -127,6 +136,9 @@
   // internal linkage.
   (void)typeid(void (*)() throw (D));
 
+  (void)typeid(DI *);
+  (void)typeid(void (DI::*)());
+
   (void)typeid(E);
   
   return typeid(getD());  
Index: lib/CodeGen/ItaniumCXXABI.cpp
===
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -3008,8 +3008,8 @@
 
 /// \brief Return the linkage that the type info and type info name constants
 /// should have for the given type.
-static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
- QualType Ty) {
+static llvm::GlobalVariable::LinkageTypes
+getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty, bool ForName = false) {
   // Itanium C++ ABI 2.9.5p7:
   //   In addition, it and all of the intermediate abi::__pointer_type_info
   //

[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146065.
EricWF marked 3 inline comments as done.
EricWF added a comment.

Address @rjmccall's comments.


https://reviews.llvm.org/D46665

Files:
  lib/CodeGen/ItaniumCXXABI.cpp
  test/CodeGenCXX/rtti-linkage.cpp

Index: test/CodeGenCXX/rtti-linkage.cpp
===
--- test/CodeGenCXX/rtti-linkage.cpp
+++ test/CodeGenCXX/rtti-linkage.cpp
@@ -1,29 +1,31 @@
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-BOTH
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | FileCheck -check-prefix=CHECK-WITH-HIDDEN -check-prefix=CHECK-BOTH %s
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | \
+// RUN:FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-BOTH \
+// RUN:   -DLINKONCE_VIS_CONSTANT='linkonce_odr constant'
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | \
+// RUN:FileCheck %s -check-prefix=CHECK-WITH-HIDDEN -check-prefix=CHECK-BOTH \
+// RUN:   -DLINKONCE_VIS_CONSTANT='linkonce_odr hidden constant'
 
 #include 
 
-// CHECK-BOTH: _ZTSP1C = internal constant
-// CHECK-BOTH: _ZTS1C = internal constant
+// CHECK-BOTH: _ZTSP1C = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTS1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTI1C = internal constant
 // CHECK-BOTH: _ZTIP1C = internal constant
-// CHECK-BOTH: _ZTSPP1C = internal constant
+// CHECK-BOTH: _ZTSPP1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIPP1C = internal constant
-// CHECK-BOTH: _ZTSM1Ci = internal constant
+// CHECK-BOTH: _ZTSM1Ci = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1Ci = internal constant
-// CHECK-BOTH: _ZTSPM1Ci = internal constant
+// CHECK-BOTH: _ZTSPM1Ci = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIPM1Ci = internal constant
-// CHECK-BOTH: _ZTSM1CS_ = internal constant
+// CHECK-BOTH: _ZTSM1CS_ = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1CS_ = internal constant
-// CHECK-BOTH: _ZTSM1CPS_ = internal constant
+// CHECK-BOTH: _ZTSM1CPS_ = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1CPS_ = internal constant
-// CHECK-BOTH: _ZTSM1A1C = internal constant
-// CHECK: _ZTS1A = linkonce_odr constant
-// CHECK-WITH-HIDDEN: _ZTS1A = linkonce_odr hidden constant
-// CHECK: _ZTI1A = linkonce_odr constant
-// CHECK-WITH-HIDDEN: _ZTI1A = linkonce_odr hidden constant
+// CHECK-BOTH: _ZTSM1A1C = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTS1A = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTI1A = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1A1C = internal constant
-// CHECK-BOTH: _ZTSM1AP1C = internal constant
+// CHECK-BOTH: _ZTSM1AP1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1AP1C = internal constant
 
 // CHECK-WITH-HIDDEN: _ZTSFN12_GLOBAL__N_11DEvE = internal constant
@@ -52,6 +54,12 @@
 // CHECK: _ZTSFvvE = linkonce_odr constant
 // CHECK: _ZTIFvvE = linkonce_odr constant
 // CHECK: _ZTIPFvvE = linkonce_odr constant
+// CHECK: _ZTSPN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTSN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTIN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTIPN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTSMN12_GLOBAL__N_12DIEFvvE = internal constant
+// CHECK: _ZTIMN12_GLOBAL__N_12DIEFvvE = internal constant
 // CHECK: _ZTSN12_GLOBAL__N_11EE = internal constant
 // CHECK: _ZTIN12_GLOBAL__N_11EE = internal constant
 // CHECK: _ZTSA10_i = linkonce_odr constant
@@ -99,9 +107,10 @@
 }
 
 namespace {
-  // D is inside an anonymous namespace, so all type information related to D should have
-  // internal linkage.
+// D and DI are inside an anonymous namespace, so all type information related
+// to both should have internal linkage.
 struct D {};
+struct DI;
 
 // E is also inside an anonymous namespace.
 enum E {};
@@ -127,6 +136,9 @@
   // internal linkage.
   (void)typeid(void (*)() throw (D));
 
+  (void)typeid(DI *);
+  (void)typeid(void (DI::*)());
+
   (void)typeid(E);
   
   return typeid(getD());  
Index: lib/CodeGen/ItaniumCXXABI.cpp
===
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -3008,20 +3008,10 @@
 
 /// Return the linkage that the type info and type info name constants
 /// should have for the given type.
-static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
- QualType Ty) {
-  // Itanium C++ ABI 2.9.5p7:
-  //   In addition, it and all of the intermediate abi::__pointer_type_info
-  //   structs in the chain down to the abi::__class_type_info for the
-  //   incomplete class type must be prevented from resolving to the
-  //   corresponding type_info structs for the complete class type, possibly
-  //   by making them local static objects. Finally, a dummy class RTTI is
-  //   generated for the

[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

@rjmccall Thank you for the quick review!


https://reviews.llvm.org/D46665



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


[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-09 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC331957: [Itanium] Emit type info names with external 
linkage. (authored by EricWF, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D46665?vs=146065&id=146069#toc

Repository:
  rC Clang

https://reviews.llvm.org/D46665

Files:
  lib/CodeGen/ItaniumCXXABI.cpp
  test/CodeGenCXX/rtti-linkage.cpp

Index: test/CodeGenCXX/rtti-linkage.cpp
===
--- test/CodeGenCXX/rtti-linkage.cpp
+++ test/CodeGenCXX/rtti-linkage.cpp
@@ -1,29 +1,31 @@
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-BOTH
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | FileCheck -check-prefix=CHECK-WITH-HIDDEN -check-prefix=CHECK-BOTH %s
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | \
+// RUN:FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-BOTH \
+// RUN:   -DLINKONCE_VIS_CONSTANT='linkonce_odr constant'
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | \
+// RUN:FileCheck %s -check-prefix=CHECK-WITH-HIDDEN -check-prefix=CHECK-BOTH \
+// RUN:   -DLINKONCE_VIS_CONSTANT='linkonce_odr hidden constant'
 
 #include 
 
-// CHECK-BOTH: _ZTSP1C = internal constant
-// CHECK-BOTH: _ZTS1C = internal constant
+// CHECK-BOTH: _ZTSP1C = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTS1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTI1C = internal constant
 // CHECK-BOTH: _ZTIP1C = internal constant
-// CHECK-BOTH: _ZTSPP1C = internal constant
+// CHECK-BOTH: _ZTSPP1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIPP1C = internal constant
-// CHECK-BOTH: _ZTSM1Ci = internal constant
+// CHECK-BOTH: _ZTSM1Ci = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1Ci = internal constant
-// CHECK-BOTH: _ZTSPM1Ci = internal constant
+// CHECK-BOTH: _ZTSPM1Ci = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIPM1Ci = internal constant
-// CHECK-BOTH: _ZTSM1CS_ = internal constant
+// CHECK-BOTH: _ZTSM1CS_ = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1CS_ = internal constant
-// CHECK-BOTH: _ZTSM1CPS_ = internal constant
+// CHECK-BOTH: _ZTSM1CPS_ = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1CPS_ = internal constant
-// CHECK-BOTH: _ZTSM1A1C = internal constant
-// CHECK: _ZTS1A = linkonce_odr constant
-// CHECK-WITH-HIDDEN: _ZTS1A = linkonce_odr hidden constant
-// CHECK: _ZTI1A = linkonce_odr constant
-// CHECK-WITH-HIDDEN: _ZTI1A = linkonce_odr hidden constant
+// CHECK-BOTH: _ZTSM1A1C = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTS1A = [[LINKONCE_VIS_CONSTANT]]
+// CHECK-BOTH: _ZTI1A = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1A1C = internal constant
-// CHECK-BOTH: _ZTSM1AP1C = internal constant
+// CHECK-BOTH: _ZTSM1AP1C = [[LINKONCE_VIS_CONSTANT]]
 // CHECK-BOTH: _ZTIM1AP1C = internal constant
 
 // CHECK-WITH-HIDDEN: _ZTSFN12_GLOBAL__N_11DEvE = internal constant
@@ -52,6 +54,12 @@
 // CHECK: _ZTSFvvE = linkonce_odr constant
 // CHECK: _ZTIFvvE = linkonce_odr constant
 // CHECK: _ZTIPFvvE = linkonce_odr constant
+// CHECK: _ZTSPN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTSN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTIN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTIPN12_GLOBAL__N_12DIE = internal constant
+// CHECK: _ZTSMN12_GLOBAL__N_12DIEFvvE = internal constant
+// CHECK: _ZTIMN12_GLOBAL__N_12DIEFvvE = internal constant
 // CHECK: _ZTSN12_GLOBAL__N_11EE = internal constant
 // CHECK: _ZTIN12_GLOBAL__N_11EE = internal constant
 // CHECK: _ZTSA10_i = linkonce_odr constant
@@ -99,12 +107,13 @@
 }
 
 namespace {
-  // D is inside an anonymous namespace, so all type information related to D should have
-  // internal linkage.
-  struct D { };
-  
-  // E is also inside an anonymous namespace.
-  enum E { };
+// D and DI are inside an anonymous namespace, so all type information related
+// to both should have internal linkage.
+struct D {};
+struct DI;
+
+// E is also inside an anonymous namespace.
+enum E {};
   
 };
 
@@ -126,7 +135,10 @@
   // The exception specification is not part of the RTTI descriptor, so it should not have
   // internal linkage.
   (void)typeid(void (*)() throw (D));
-  
+
+  (void)typeid(DI *);
+  (void)typeid(void (DI::*)());
+
   (void)typeid(E);
   
   return typeid(getD());  
Index: lib/CodeGen/ItaniumCXXABI.cpp
===
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -3008,8 +3008,46 @@
 
 /// Return the linkage that the type info and type info name constants
 /// should have for the given type.
-static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
- QualType Ty) {
+static std::pair
+getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
+  llvm

[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF reopened this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

Re-opening. I had to revert the last commit since it seemed to cause error 
(which looked unrelated?) on ppc64le-linux.


Repository:
  rC Clang

https://reviews.llvm.org/D46665



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


[PATCH] D45680: [C++2a] Implement operator<=> Part 2: Operator Rewritting and Overload Resolution.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146090.
EricWF added a comment.

Remove a bunch of nonsense this patch originally had. Specifically remove the 
bits of overload resolution which disambiguated rewritten expressions after the 
fact; Instead attempt to validate that the return type of the three-way 
comparison operand in a rewritten relational or equality can be used with the 
the specified operand (e.g. `std::strong_equality` cannot be used with a 
relational operator).


https://reviews.llvm.org/D45680

Files:
  include/clang/AST/ComparisonCategories.h
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Sema/Overload.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ComparisonCategories.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/cxx2a-compare.cpp
  test/SemaCXX/compare-cxx2a.cpp

Index: test/SemaCXX/compare-cxx2a.cpp
===
--- test/SemaCXX/compare-cxx2a.cpp
+++ test/SemaCXX/compare-cxx2a.cpp
@@ -292,20 +292,21 @@
 
 template 
 struct Tag {};
-// expected-note@+1 {{candidate}}
-Tag<0> operator<=>(EnumA, EnumA) {
-  return {};
+std::strong_ordering operator<=>(EnumA, EnumA) {
+  return std::strong_ordering::equal;
 }
-Tag<1> operator<=>(EnumA, EnumB) {
-  return {};
+// expected-note@+1 {{candidate function}},
+std::strong_ordering operator<=>(EnumA a, EnumB b) {
+  return ((int)a <=> (int)b);
 }
 
 void test_enum_ovl_provided() {
   auto r1 = (EnumA::A <=> EnumA::A);
-  ASSERT_EXPR_TYPE(r1, Tag<0>);
+  ASSERT_EXPR_TYPE(r1, std::strong_ordering);
   auto r2 = (EnumA::A <=> EnumB::B);
-  ASSERT_EXPR_TYPE(r2, Tag<1>);
-  (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}}
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+  (void)(EnumB::B <=> EnumA::A); // OK, chooses reverse order synthesized candidate.
+  (void)(EnumB::B <=> EnumC::C); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumC')}}
 }
 
 void enum_float_test() {
@@ -421,3 +422,114 @@
 }
 
 } // namespace ComplexTest
+
+namespace TestRewritting {
+
+struct T {
+  int x;
+  // expected-note@+1 {{candidate}}
+  constexpr std::strong_ordering operator<=>(T y) const {
+return (x <=> y.x);
+  }
+};
+
+struct U {
+  int x;
+  // FIXME: This diagnostic is wrong-ish.
+  // expected-note@+1 {{candidate function not viable: requires single argument 'y', but 2 arguments were provided}}
+  constexpr std::strong_equality operator<=>(T y) const {
+if (x == y.x)
+  return std::strong_equality::equal;
+return std::strong_equality::nonequal;
+  }
+};
+
+struct X { int x; };
+struct Y { int x; };
+template 
+struct Tag {};
+// expected-note@+1 2 {{candidate}}
+Tag<0> operator<=>(X, Y) {
+  return {};
+}
+// expected-note@+1 2 {{candidate}}
+constexpr auto operator<=>(Y y, X x) {
+  return y.x <=> x.x;
+}
+
+void foo() {
+  T t{42};
+  T t2{0};
+  U u{101};
+  auto r1 = (t <=> u);
+  ASSERT_EXPR_TYPE(r1, std::strong_equality);
+  auto r2 = (t <=> t2);
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+
+  auto r3 = t == u;
+  ASSERT_EXPR_TYPE(r3, bool);
+
+  (void)(t < u); // expected-error {{invalid operands to binary expression ('TestRewritting::T' and 'TestRewritting::U')}}
+
+  constexpr X x{1};
+  constexpr Y y{2};
+  constexpr auto r4 = (y < x);
+  static_assert(r4 == false);
+  constexpr auto r5 = (x < y);
+  static_assert(r5 == true);
+}
+
+} // namespace TestRewritting
+
+// The implicit object parameter is not considered when performing partial
+// ordering. That makes the reverse synthesized candidates ambiguous with the
+// rewritten candidates if any of them resolve to a member function.
+namespace TestOvlMatchingIgnoresImplicitObject {
+struct U;
+struct T {
+  std::strong_ordering operator<=>(U const &RHS) const;
+};
+struct U {
+  std::strong_ordering operator<=>(T const &RHS) const;
+};
+
+struct V {
+  int x;
+};
+auto operator<=>(V const &LHS, V &&RHS) { // expected-note 4 {{candidate}}
+  return LHS.x <=> RHS.x;
+}
+auto operator<(V const &, V &&) { // expected-note {{candidate}}
+  return std::strong_equality::equal;
+}
+
+void test() {
+  // expected-error@+1 {{use of overloaded operator '<' is ambiguous}}
+  (void)(T{} < U{});
+  // expected-error@+1 {{use of overloaded operator '<' is ambiguous}}
+  (void)(V{} < V{});
+  // expected-error@+1 {{use of overloaded operat

[PATCH] D46665: [Itanium] Emit type info names with external linkage.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC332028: [Itanium] Emit type info names with external 
linkage. (authored by EricWF, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D46665

Files:
  lib/CodeGen/ItaniumCXXABI.cpp
  test/CodeGenCXX/rtti-linkage.cpp

Index: lib/CodeGen/ItaniumCXXABI.cpp
===
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -3008,8 +3008,46 @@
 
 /// Return the linkage that the type info and type info name constants
 /// should have for the given type.
-static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
- QualType Ty) {
+static std::pair
+getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
+  llvm::GlobalValue::LinkageTypes TypeLinkage = [&]() {
+switch (Ty->getLinkage()) {
+case NoLinkage:
+case InternalLinkage:
+case UniqueExternalLinkage:
+  return llvm::GlobalValue::InternalLinkage;
+
+case VisibleNoLinkage:
+case ModuleInternalLinkage:
+case ModuleLinkage:
+case ExternalLinkage:
+  // RTTI is not enabled, which means that this type info struct is going
+  // to be used for exception handling. Give it linkonce_odr linkage.
+  if (!CGM.getLangOpts().RTTI)
+return llvm::GlobalValue::LinkOnceODRLinkage;
+
+  if (const RecordType *Record = dyn_cast(Ty)) {
+const CXXRecordDecl *RD = cast(Record->getDecl());
+if (RD->hasAttr())
+  return llvm::GlobalValue::WeakODRLinkage;
+if (CGM.getTriple().isWindowsItaniumEnvironment())
+  if (RD->hasAttr() &&
+  ShouldUseExternalRTTIDescriptor(CGM, Ty))
+return llvm::GlobalValue::ExternalLinkage;
+// MinGW always uses LinkOnceODRLinkage for type info.
+if (RD->isCompleteDefinition() && RD->isDynamicClass() &&
+!CGM.getContext()
+ .getTargetInfo()
+ .getTriple()
+ .isWindowsGNUEnvironment())
+  return CGM.getVTableLinkage(RD);
+  }
+
+  return llvm::GlobalValue::LinkOnceODRLinkage;
+}
+llvm_unreachable("Invalid linkage!");
+  }();
   // Itanium C++ ABI 2.9.5p7:
   //   In addition, it and all of the intermediate abi::__pointer_type_info
   //   structs in the chain down to the abi::__class_type_info for the
@@ -3020,44 +3058,8 @@
   //   complete class RTTI (because the latter need not exist), possibly by
   //   making it a local static object.
   if (ContainsIncompleteClassType(Ty))
-return llvm::GlobalValue::InternalLinkage;
-
-  switch (Ty->getLinkage()) {
-  case NoLinkage:
-  case InternalLinkage:
-  case UniqueExternalLinkage:
-return llvm::GlobalValue::InternalLinkage;
-
-  case VisibleNoLinkage:
-  case ModuleInternalLinkage:
-  case ModuleLinkage:
-  case ExternalLinkage:
-// RTTI is not enabled, which means that this type info struct is going
-// to be used for exception handling. Give it linkonce_odr linkage.
-if (!CGM.getLangOpts().RTTI)
-  return llvm::GlobalValue::LinkOnceODRLinkage;
-
-if (const RecordType *Record = dyn_cast(Ty)) {
-  const CXXRecordDecl *RD = cast(Record->getDecl());
-  if (RD->hasAttr())
-return llvm::GlobalValue::WeakODRLinkage;
-  if (CGM.getTriple().isWindowsItaniumEnvironment())
-if (RD->hasAttr() &&
-ShouldUseExternalRTTIDescriptor(CGM, Ty))
-  return llvm::GlobalValue::ExternalLinkage;
-  // MinGW always uses LinkOnceODRLinkage for type info.
-  if (RD->isDynamicClass() &&
-  !CGM.getContext()
-   .getTargetInfo()
-   .getTriple()
-   .isWindowsGNUEnvironment())
-return CGM.getVTableLinkage(RD);
-}
-
-return llvm::GlobalValue::LinkOnceODRLinkage;
-  }
-
-  llvm_unreachable("Invalid linkage!");
+return {llvm::GlobalValue::InternalLinkage, TypeLinkage};
+  return {TypeLinkage, TypeLinkage};
 }
 
 llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force,
@@ -3084,23 +3086,25 @@
 return GetAddrOfExternalRTTIDescriptor(Ty);
 
   // Emit the standard library with external linkage.
-  llvm::GlobalVariable::LinkageTypes Linkage;
+  llvm::GlobalVariable::LinkageTypes InfoLinkage, NameLinkage;
   if (IsStdLib)
-Linkage = llvm::GlobalValue::ExternalLinkage;
-  else
-Linkage = getTypeInfoLinkage(CGM, Ty);
-
+InfoLinkage = NameLinkage = llvm::GlobalValue::ExternalLinkage;
+  else {
+auto LinkagePair = getTypeInfoLinkage(CGM, Ty);
+InfoLinkage = LinkagePair.first;
+NameLinkage = LinkagePair.second;
+  }
   // Add the vtable pointer.
   BuildVTablePointer(cast(Ty));
 
   // And the name.
-  llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
+  llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, NameLinkage);
   llvm::Constant *TypeNameField;
 
   // If we're

[PATCH] D45680: [C++2a] Implement operator<=> Part 2: Operator Rewritting and Overload Resolution.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added inline comments.



Comment at: include/clang/AST/ExprCXX.h:4218-4226
+  struct ComparisonBits {
+/// Whether this rewritten comparison expression has reverse-order
+/// parameters.
+unsigned IsSynthesized : 1;
+  };
+
+  union ExtraRewrittenBits {

rsmith wrote:
> I don't think you need this.
I guess it's just future proofing, or an attempt to demonstrate how the class 
may be generalized. I'll remove it for now.



Comment at: include/clang/Sema/Overload.h:938
+/// exited.
+struct RewrittenCandidateContextGuard {
+  RewrittenCandidateContextGuard(OverloadCandidateSet &CS)

rsmith wrote:
> EricWF wrote:
> > This is unneeded. As long as the rewritten candidates are added last, 
> > restoring the `Functions` member is unneeded. 
> Please instead extend the `Functions` set to be a set of 
> `PointerIntPair`.
Sure. I'll get that done.

There are two options here:

(A) Keep the guard object. Store the RewrittenOverloadCandidateKind which we're 
currently adding candidates for, and have `addCandidate` and `isNewCandidate` 
handle the ROC.

(B) Change all of the `AddFooCandidates` interfaces in Sema to take yet another 
default parameter, and pass it around everywhere.

Which would you prefer @rsmith?



Comment at: include/clang/Sema/Overload.h:81-83
+ROC_Rewritten,
+/// Both rewritten and synthesized.
+ROC_Synthesized

rsmith wrote:
> These names are not very good. The standard describes both these cases as 
> "rewritten", so `ROC_Rewritten` is ambiguous, and it says "a synthesized 
> candidate with reversed order of parameters", not merely "synthesized" (which 
> would fail to communicate what's going on).
> 
> How about `ROC_AsThreeWayComparison` and `ROC_AsReversedThreeWayComparison` 
> or similar?
Sounds good to me.



Comment at: lib/Sema/SemaOverload.cpp:12543-12547
+  Expr *Original = new (S.Context)
+  BinaryOperator(OpaqueValueExpr::Create(S.Context, Args[0]),
+ OpaqueValueExpr::Create(S.Context, Args[1]), Opc,
+ Rewritten->getType(), Rewritten->getValueKind(),
+ Rewritten->getObjectKind(), OpLoc, S.FPFeatures);

rsmith wrote:
> If you want to model this as a generic (syntactic form, semantic form) pair, 
> the syntactic form needs to preserve enough information that `TreeTransform` 
> on it can recreate the semantic form. That means you need to store a 
> `CXXOperatorCallExpr` to an `UnresolvedLookupExpr` to hold `Fns` if `Fns` is 
> not empty (see the code at the start of `CreateOverloadedBinOp` that deals 
> with the type-dependent case for an example of what you would need to do).
> 
> Though perhaps this is as good a reason as any to give up the idea of a 
> generic rewrite expression and add something specific to a three-way 
> comparison rewrite; the representation needed to fit this into a generic 
> rewrite mechanism is very unwieldy. (If we add any more forms of rewritten 
> operator later, we can consider whether a generalization is worthwhile.)
I think the FIXME comment may be incorrect.

Shouldn't this be sufficient since we never actually build the rewritten 
expression until the input expressions are no longer type dependent?
Additionally, with this representation `TreeTransform` can transform the 
semantic form, since (if I'm correct), a rebuild should never re-perform 
overload resolution to choose how to rewrite the initial expression. (Does that 
make sense, and is it correct?)



I'll go ahead and start converting to a less-general representation of the 
rewritten expression.


https://reviews.llvm.org/D45680



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


[PATCH] D45680: [C++2a] Implement operator<=> Part 2: Operator Rewritting and Overload Resolution.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146274.
EricWF marked 13 inline comments as done.
EricWF added a comment.

- Change `CXXRewrittenExpr` to be a non-general wrapper only for rewritten 
comparison operators.
- Start fixing and improving overload resolution diagnostics.


https://reviews.llvm.org/D45680

Files:
  include/clang/AST/ComparisonCategories.h
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/StmtNodes.td
  include/clang/Sema/Overload.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ComparisonCategories.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/cxx2a-compare.cpp
  test/SemaCXX/compare-cxx2a.cpp

Index: test/SemaCXX/compare-cxx2a.cpp
===
--- test/SemaCXX/compare-cxx2a.cpp
+++ test/SemaCXX/compare-cxx2a.cpp
@@ -292,20 +292,21 @@
 
 template 
 struct Tag {};
-// expected-note@+1 {{candidate}}
-Tag<0> operator<=>(EnumA, EnumA) {
-  return {};
+std::strong_ordering operator<=>(EnumA, EnumA) {
+  return std::strong_ordering::equal;
 }
-Tag<1> operator<=>(EnumA, EnumB) {
-  return {};
+// expected-note@+1 {{candidate function}},
+std::strong_ordering operator<=>(EnumA a, EnumB b) {
+  return ((int)a <=> (int)b);
 }
 
 void test_enum_ovl_provided() {
   auto r1 = (EnumA::A <=> EnumA::A);
-  ASSERT_EXPR_TYPE(r1, Tag<0>);
+  ASSERT_EXPR_TYPE(r1, std::strong_ordering);
   auto r2 = (EnumA::A <=> EnumB::B);
-  ASSERT_EXPR_TYPE(r2, Tag<1>);
-  (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}}
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+  (void)(EnumB::B <=> EnumA::A); // OK, chooses reverse order synthesized candidate.
+  (void)(EnumB::B <=> EnumC::C); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumC')}}
 }
 
 void enum_float_test() {
@@ -421,3 +422,114 @@
 }
 
 } // namespace ComplexTest
+
+namespace TestRewritting {
+
+struct T {
+  int x;
+  // expected-note@+1 {{candidate}}
+  constexpr std::strong_ordering operator<=>(T y) const {
+return (x <=> y.x);
+  }
+};
+
+struct U {
+  int x;
+  // FIXME: This diagnostic is wrong-ish.
+  // expected-note@+1 {{candidate function not viable: requires single argument 'y', but 2 arguments were provided}}
+  constexpr std::strong_equality operator<=>(T y) const {
+if (x == y.x)
+  return std::strong_equality::equal;
+return std::strong_equality::nonequal;
+  }
+};
+
+struct X { int x; };
+struct Y { int x; };
+template 
+struct Tag {};
+
+Tag<0> operator<=>(X, Y) {
+  return {};
+}
+
+constexpr auto operator<=>(Y y, X x) {
+  return y.x <=> x.x;
+}
+
+void foo() {
+  T t{42};
+  T t2{0};
+  U u{101};
+  auto r1 = (t <=> u);
+  ASSERT_EXPR_TYPE(r1, std::strong_equality);
+  auto r2 = (t <=> t2);
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+
+  auto r3 = t == u;
+  ASSERT_EXPR_TYPE(r3, bool);
+
+  (void)(t < u); // expected-error {{invalid operands to binary expression ('TestRewritting::T' and 'TestRewritting::U')}}
+
+  constexpr X x{1};
+  constexpr Y y{2};
+  constexpr auto r4 = (y < x);
+  static_assert(r4 == false);
+  constexpr auto r5 = (x < y);
+  static_assert(r5 == true);
+}
+
+} // namespace TestRewritting
+
+// The implicit object parameter is not considered when performing partial
+// ordering. That makes the reverse synthesized candidates ambiguous with the
+// rewritten candidates if any of them resolve to a member function.
+namespace TestOvlMatchingIgnoresImplicitObject {
+struct U;
+struct T {
+  std::strong_ordering operator<=>(U const &RHS) const;
+};
+struct U {
+  std::strong_ordering operator<=>(T const &RHS) const = delete;
+};
+
+struct V {
+  int x;
+};
+auto operator<=>(V const &LHS, V &&RHS) { // expected-note 4 {{candidate}}
+  return LHS.x <=> RHS.x;
+}
+auto operator<(V const &, V &&) { // expected-note {{candidate}}
+  return std::strong_equality::equal;
+}
+
+void test() {
+  // OK. selects T::operator<=>(U)
+  (void)(T{} < U{});
+  // expected-error@+1 {{use of overloaded operator '<' is ambiguous}}
+  (void)(V{} < V{});
+  // expected-error@+1 {{use of overloaded operator '<=>' is ambiguous}}
+  (void)(V{} <=> V{});
+}
+
+} // namespace TestOvlMatchingIgnoresImplicitObject
+
+namespace TestRewrittenTemplate {
+
+template 
+auto test(T const &LHS, T const &RHS) {
+  // expected-error@+1 {{invalid opera

[PATCH] D45680: [C++2a] Implement operator<=> Part 2: Operator Rewritting and Overload Resolution.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 2 inline comments as done.
EricWF added inline comments.



Comment at: lib/Sema/SemaOverload.cpp:12543-12547
+  Expr *Original = new (S.Context)
+  BinaryOperator(OpaqueValueExpr::Create(S.Context, Args[0]),
+ OpaqueValueExpr::Create(S.Context, Args[1]), Opc,
+ Rewritten->getType(), Rewritten->getValueKind(),
+ Rewritten->getObjectKind(), OpLoc, S.FPFeatures);

EricWF wrote:
> rsmith wrote:
> > If you want to model this as a generic (syntactic form, semantic form) 
> > pair, the syntactic form needs to preserve enough information that 
> > `TreeTransform` on it can recreate the semantic form. That means you need 
> > to store a `CXXOperatorCallExpr` to an `UnresolvedLookupExpr` to hold `Fns` 
> > if `Fns` is not empty (see the code at the start of `CreateOverloadedBinOp` 
> > that deals with the type-dependent case for an example of what you would 
> > need to do).
> > 
> > Though perhaps this is as good a reason as any to give up the idea of a 
> > generic rewrite expression and add something specific to a three-way 
> > comparison rewrite; the representation needed to fit this into a generic 
> > rewrite mechanism is very unwieldy. (If we add any more forms of rewritten 
> > operator later, we can consider whether a generalization is worthwhile.)
> I think the FIXME comment may be incorrect.
> 
> Shouldn't this be sufficient since we never actually build the rewritten 
> expression until the input expressions are no longer type dependent?
> Additionally, with this representation `TreeTransform` can transform the 
> semantic form, since (if I'm correct), a rebuild should never re-perform 
> overload resolution to choose how to rewrite the initial expression. (Does 
> that make sense, and is it correct?)
> 
> 
> 
> I'll go ahead and start converting to a less-general representation of the 
> rewritten expression.
Nevermind. This was answered offline.


https://reviews.llvm.org/D45680



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


[PATCH] D45680: [C++2a] Implement operator<=> Part 2: Operator Rewritting and Overload Resolution.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 11 inline comments as done.
EricWF added inline comments.



Comment at: include/clang/AST/Stmt.h:254
+
+unsigned Kind : 1;
+  };

rsmith wrote:
> I don't think you need this either.
Does keeping it help save bits in `CXXRewrittenOperatorExpr`?


https://reviews.llvm.org/D45680



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


[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF created this revision.
EricWF added reviewers: rsmith, rjmccall, aaron.ballman.
Herald added a reviewer: a.sidorin.

There are cases where the same string or select is repeated verbatim in a lot 
of diagnostics. This can be a pain to maintain and update. However, Tablegen 
provides no way stash the common text somewhere and reuse it in the 
diagnostics, until now!

This patch allows diagnostic texts to contain `%sub{}`, where 
`` names a Tablegen record of type `TextSubstitution`. These 
substitutions are done early, before the diagnostic string is otherwise 
processed. All `%sub` modifiers will be replaced before the diagnostic 
definitions are emitted.

Thoughts?

I'll add tests once there is consensus that this change should proceed.


Repository:
  rC Clang

https://reviews.llvm.org/D46740

Files:
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,13 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Regex.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -455,6 +456,39 @@
   return ClsName == "CLASS_REMARK";
 }
 
+static void substituteDiagText(Record *Diag, StringMap SubsMap) {
+  llvm::Regex RE("%sub{[^}]*}");
+  std::string Error;
+  ((void)Error);
+  assert(RE.isValid(Error) && RE.getNumMatches() == 0);
+
+  RecordVal *RV = Diag->getValue("Text");
+  std::string Text = RV->getValue()->getAsString();
+
+  unsigned Count = 0;
+  SmallVector Matches;
+  while (RE.match(Text, &Matches)) {
+++Count;
+assert(Matches.size() == 1);
+StringRef M = Matches[0];
+std::pair Range(M.data() - Text.data(), M.size());
+
+assert(Text.size() > Range.first + Range.second);
+StringRef Found(Text);
+
+Found = Found.substr(Range.first, Range.second);
+StringRef FoundName = Found.substr(5, Found.size() - 6);
+Record *S = SubsMap.lookup(FoundName);
+if (!S) {
+  PrintFatalError(Diag->getLoc(), "Diag " + Diag->getName() +
+  " has no substitution for: " + Found);
+}
+Text.replace(Range.first, Range.second,
+ S->getValueAsString("Substitution"));
+  }
+  RV->setValue(StringInit::get(Text));
+}
+
 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
 /// declarations of Clang diagnostics.
 namespace clang {
@@ -470,8 +504,14 @@
 OS << "#endif\n\n";
   }
 
-  const std::vector &Diags =
-Records.getAllDerivedDefinitions("Diagnostic");
+  std::vector Substitutions =
+  Records.getAllDerivedDefinitions("TextSubstitution");
+  StringMap SubsMap;
+  for (auto *R : Substitutions)
+SubsMap.try_emplace(R->getName(), R);
+
+  std::vector Diags = Records.getAllDerivedDefinitions("Diagnostic");
+  llvm::for_each(Diags, [&](Record *R) { substituteDiagText(R, SubsMap); });
 
   std::vector DiagGroups
 = Records.getAllDerivedDefinitions("DiagGroup");
@@ -953,6 +993,9 @@
 StringRef Modifier = Text.slice(0, ModLength);
 Text = Text.slice(ModLength, StringRef::npos);
 
+assert(Modifier != "sub" &&
+   "substitutions should have already taken place!");
+
 // FIXME: Handle %ordinal here.
 if (Modifier == "select" || Modifier == "plural") {
   DiagText::SelectPiece Select;
@@ -1208,9 +1251,16 @@
   }
 
   OS << Documentation->getValueAsString("Intro") << "\n";
+  std::vector Substitutions =
+  Records.getAllDerivedDefinitions("TextSubstitution");
+  StringMap SubsMap;
+  for (Record *R : Substitutions)
+SubsMap.try_emplace(R->getName(), R);
 
   std::vector Diags =
   Records.getAllDerivedDefinitions("Diagnostic");
+  llvm::for_each(Diags, [&](Record *R) { substituteDiagText(R, SubsMap); });
+
   std::vector DiagGroups =
   Records.getAllDerivedDefinitions("DiagGroup");
   llvm::sort(DiagGroups.begin(), DiagGroups.end(), diagGroupBeforeByName);
@@ -1300,6 +1350,7 @@
 Severity[0] = tolower(Severity[0]);
 if (Severity == "ignored")
   Severity = IsRemarkGroup ? "remark" : "warning";
+
 writeDiagnosticText(Severity, D->getValueAsString("Text"), OS);
   }
 }
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -3613,41 +3613,39 @@
 def note_ovl_candidate_non_deduced_mismatch_qua

[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146279.
EricWF added a comment.

Fix copy paste error.


https://reviews.llvm.org/D46740

Files:
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,13 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Regex.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -455,6 +456,39 @@
   return ClsName == "CLASS_REMARK";
 }
 
+static void substituteDiagText(Record *Diag, StringMap SubsMap) {
+  llvm::Regex RE("%sub{[^}]*}");
+  std::string Error;
+  ((void)Error);
+  assert(RE.isValid(Error) && RE.getNumMatches() == 0);
+
+  RecordVal *RV = Diag->getValue("Text");
+  std::string Text = RV->getValue()->getAsString();
+
+  unsigned Count = 0;
+  SmallVector Matches;
+  while (RE.match(Text, &Matches)) {
+++Count;
+assert(Matches.size() == 1);
+StringRef M = Matches[0];
+std::pair Range(M.data() - Text.data(), M.size());
+
+assert(Text.size() > Range.first + Range.second);
+StringRef Found(Text);
+
+Found = Found.substr(Range.first, Range.second);
+StringRef FoundName = Found.substr(5, Found.size() - 6);
+Record *S = SubsMap.lookup(FoundName);
+if (!S) {
+  PrintFatalError(Diag->getLoc(), "Diag " + Diag->getName() +
+  " has no substitution for: " + Found);
+}
+Text.replace(Range.first, Range.second,
+ S->getValueAsString("Substitution"));
+  }
+  RV->setValue(StringInit::get(Text));
+}
+
 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
 /// declarations of Clang diagnostics.
 namespace clang {
@@ -470,8 +504,14 @@
 OS << "#endif\n\n";
   }
 
-  const std::vector &Diags =
-Records.getAllDerivedDefinitions("Diagnostic");
+  std::vector Substitutions =
+  Records.getAllDerivedDefinitions("TextSubstitution");
+  StringMap SubsMap;
+  for (auto *R : Substitutions)
+SubsMap.try_emplace(R->getName(), R);
+
+  std::vector Diags = Records.getAllDerivedDefinitions("Diagnostic");
+  llvm::for_each(Diags, [&](Record *R) { substituteDiagText(R, SubsMap); });
 
   std::vector DiagGroups
 = Records.getAllDerivedDefinitions("DiagGroup");
@@ -953,6 +993,9 @@
 StringRef Modifier = Text.slice(0, ModLength);
 Text = Text.slice(ModLength, StringRef::npos);
 
+assert(Modifier != "sub" &&
+   "substitutions should have already taken place!");
+
 // FIXME: Handle %ordinal here.
 if (Modifier == "select" || Modifier == "plural") {
   DiagText::SelectPiece Select;
@@ -1208,9 +1251,16 @@
   }
 
   OS << Documentation->getValueAsString("Intro") << "\n";
+  std::vector Substitutions =
+  Records.getAllDerivedDefinitions("TextSubstitution");
+  StringMap SubsMap;
+  for (Record *R : Substitutions)
+SubsMap.try_emplace(R->getName(), R);
 
   std::vector Diags =
   Records.getAllDerivedDefinitions("Diagnostic");
+  llvm::for_each(Diags, [&](Record *R) { substituteDiagText(R, SubsMap); });
+
   std::vector DiagGroups =
   Records.getAllDerivedDefinitions("DiagGroup");
   llvm::sort(DiagGroups.begin(), DiagGroups.end(), diagGroupBeforeByName);
@@ -1300,6 +1350,7 @@
 Severity[0] = tolower(Severity[0]);
 if (Severity == "ignored")
   Severity = IsRemarkGroup ? "remark" : "warning";
+
 writeDiagnosticText(Severity, D->getValueAsString("Text"), OS);
   }
 }
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -3613,41 +3613,39 @@
 def note_ovl_candidate_non_deduced_mismatch_qualified : Note<
 "candidate template ignored: could not match %q0 against %q1">;
 
-// Note that we don't treat templates differently for this diagnostic.
-def note_ovl_candidate_arity : Note<"candidate "
+def select_ovl_candidate_kind : TextSubstitution<
 "%select{function|function|constructor|function|function|constructor|"
 "constructor (the implicit default constructor)|"
 "constructor (the implicit copy constructor)|"
 "constructor (the implicit move constructor)|"
 "function (the implicit copy assignment operator)|"
 "function (the implicit move assignment operator)|"
 "inherited constructor|"
-"inherited constructor}0 %select{|template 

[PATCH] D45680: [C++2a] Implement operator<=> Part 2: Operator Rewritting and Overload Resolution.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146280.
EricWF added a comment.

Do better english in diagnostics.


https://reviews.llvm.org/D45680

Files:
  include/clang/AST/ComparisonCategories.h
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/StmtNodes.td
  include/clang/Sema/Overload.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ComparisonCategories.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/cxx2a-compare.cpp
  test/SemaCXX/compare-cxx2a.cpp

Index: test/SemaCXX/compare-cxx2a.cpp
===
--- test/SemaCXX/compare-cxx2a.cpp
+++ test/SemaCXX/compare-cxx2a.cpp
@@ -292,20 +292,21 @@
 
 template 
 struct Tag {};
-// expected-note@+1 {{candidate}}
-Tag<0> operator<=>(EnumA, EnumA) {
-  return {};
+std::strong_ordering operator<=>(EnumA, EnumA) {
+  return std::strong_ordering::equal;
 }
-Tag<1> operator<=>(EnumA, EnumB) {
-  return {};
+// expected-note@+1 {{candidate function}},
+std::strong_ordering operator<=>(EnumA a, EnumB b) {
+  return ((int)a <=> (int)b);
 }
 
 void test_enum_ovl_provided() {
   auto r1 = (EnumA::A <=> EnumA::A);
-  ASSERT_EXPR_TYPE(r1, Tag<0>);
+  ASSERT_EXPR_TYPE(r1, std::strong_ordering);
   auto r2 = (EnumA::A <=> EnumB::B);
-  ASSERT_EXPR_TYPE(r2, Tag<1>);
-  (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}}
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+  (void)(EnumB::B <=> EnumA::A); // OK, chooses reverse order synthesized candidate.
+  (void)(EnumB::B <=> EnumC::C); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumC')}}
 }
 
 void enum_float_test() {
@@ -421,3 +422,114 @@
 }
 
 } // namespace ComplexTest
+
+namespace TestRewritting {
+
+struct T {
+  int x;
+  // expected-note@+1 {{candidate}}
+  constexpr std::strong_ordering operator<=>(T y) const {
+return (x <=> y.x);
+  }
+};
+
+struct U {
+  int x;
+  // FIXME: This diagnostic is wrong-ish.
+  // expected-note@+1 {{candidate function not viable: requires single argument 'y', but 2 arguments were provided}}
+  constexpr std::strong_equality operator<=>(T y) const {
+if (x == y.x)
+  return std::strong_equality::equal;
+return std::strong_equality::nonequal;
+  }
+};
+
+struct X { int x; };
+struct Y { int x; };
+template 
+struct Tag {};
+
+Tag<0> operator<=>(X, Y) {
+  return {};
+}
+
+constexpr auto operator<=>(Y y, X x) {
+  return y.x <=> x.x;
+}
+
+void foo() {
+  T t{42};
+  T t2{0};
+  U u{101};
+  auto r1 = (t <=> u);
+  ASSERT_EXPR_TYPE(r1, std::strong_equality);
+  auto r2 = (t <=> t2);
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+
+  auto r3 = t == u;
+  ASSERT_EXPR_TYPE(r3, bool);
+
+  (void)(t < u); // expected-error {{invalid operands to binary expression ('TestRewritting::T' and 'TestRewritting::U')}}
+
+  constexpr X x{1};
+  constexpr Y y{2};
+  constexpr auto r4 = (y < x);
+  static_assert(r4 == false);
+  constexpr auto r5 = (x < y);
+  static_assert(r5 == true);
+}
+
+} // namespace TestRewritting
+
+// The implicit object parameter is not considered when performing partial
+// ordering. That makes the reverse synthesized candidates ambiguous with the
+// rewritten candidates if any of them resolve to a member function.
+namespace TestOvlMatchingIgnoresImplicitObject {
+struct U;
+struct T {
+  std::strong_ordering operator<=>(U const &RHS) const;
+};
+struct U {
+  std::strong_ordering operator<=>(T const &RHS) const = delete;
+};
+
+struct V {
+  int x;
+};
+auto operator<=>(V const &LHS, V &&RHS) { // expected-note 4 {{candidate}}
+  return LHS.x <=> RHS.x;
+}
+auto operator<(V const &, V &&) { // expected-note {{candidate}}
+  return std::strong_equality::equal;
+}
+
+void test() {
+  // OK. selects T::operator<=>(U)
+  (void)(T{} < U{});
+  // expected-error@+1 {{use of overloaded operator '<' is ambiguous}}
+  (void)(V{} < V{});
+  // expected-error@+1 {{use of overloaded operator '<=>' is ambiguous}}
+  (void)(V{} <=> V{});
+}
+
+} // namespace TestOvlMatchingIgnoresImplicitObject
+
+namespace TestRewrittenTemplate {
+
+template 
+auto test(T const &LHS, T const &RHS) {
+  // expected-error@+1 {{invalid operands to binary expression ('const TestRewrittenTemplate::None'}}
+  return LHS < RHS;
+}
+struct None {};
+template auto test(None const &, None const &); // expected-no

[PATCH] D45680: [C++2a] Implement operator<=> Part 2: Operator Rewritting and Overload Resolution.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146281.
EricWF added a comment.

Fix fetching the correct source location information in 
`CXXRewrittenOperatorExpr`.


https://reviews.llvm.org/D45680

Files:
  include/clang/AST/ComparisonCategories.h
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/StmtNodes.td
  include/clang/Sema/Overload.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ComparisonCategories.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/cxx2a-compare.cpp
  test/SemaCXX/compare-cxx2a.cpp

Index: test/SemaCXX/compare-cxx2a.cpp
===
--- test/SemaCXX/compare-cxx2a.cpp
+++ test/SemaCXX/compare-cxx2a.cpp
@@ -292,20 +292,21 @@
 
 template 
 struct Tag {};
-// expected-note@+1 {{candidate}}
-Tag<0> operator<=>(EnumA, EnumA) {
-  return {};
+std::strong_ordering operator<=>(EnumA, EnumA) {
+  return std::strong_ordering::equal;
 }
-Tag<1> operator<=>(EnumA, EnumB) {
-  return {};
+// expected-note@+1 {{candidate function}},
+std::strong_ordering operator<=>(EnumA a, EnumB b) {
+  return ((int)a <=> (int)b);
 }
 
 void test_enum_ovl_provided() {
   auto r1 = (EnumA::A <=> EnumA::A);
-  ASSERT_EXPR_TYPE(r1, Tag<0>);
+  ASSERT_EXPR_TYPE(r1, std::strong_ordering);
   auto r2 = (EnumA::A <=> EnumB::B);
-  ASSERT_EXPR_TYPE(r2, Tag<1>);
-  (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}}
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+  (void)(EnumB::B <=> EnumA::A); // OK, chooses reverse order synthesized candidate.
+  (void)(EnumB::B <=> EnumC::C); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumC')}}
 }
 
 void enum_float_test() {
@@ -421,3 +422,113 @@
 }
 
 } // namespace ComplexTest
+
+namespace TestRewritting {
+
+struct T {
+  int x;
+  // expected-note@+1 {{candidate}}
+  constexpr std::strong_ordering operator<=>(T y) const {
+return (x <=> y.x);
+  }
+};
+
+struct U {
+  int x;
+  // FIXME(EricWF2
+  constexpr std::strong_equality operator<=>(T y) const {
+if (x == y.x)
+  return std::strong_equality::equal;
+return std::strong_equality::nonequal;
+  }
+};
+
+struct X { int x; };
+struct Y { int x; };
+template 
+struct Tag {};
+
+Tag<0> operator<=>(X, Y) {
+  return {};
+}
+
+constexpr auto operator<=>(Y y, X x) {
+  return y.x <=> x.x;
+}
+
+void foo() {
+  T t{42};
+  T t2{0};
+  U u{101};
+  auto r1 = (t <=> u);
+  ASSERT_EXPR_TYPE(r1, std::strong_equality);
+  auto r2 = (t <=> t2);
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+
+  auto r3 = t == u;
+  ASSERT_EXPR_TYPE(r3, bool);
+
+  (void)(t < u); // expected-error {{invalid operands to binary expression ('TestRewritting::T' and 'TestRewritting::U')}}
+
+  constexpr X x{1};
+  constexpr Y y{2};
+  constexpr auto r4 = (y < x);
+  static_assert(r4 == false);
+  constexpr auto r5 = (x < y);
+  static_assert(r5 == true);
+}
+
+} // namespace TestRewritting
+
+// The implicit object parameter is not considered when performing partial
+// ordering. That makes the reverse synthesized candidates ambiguous with the
+// rewritten candidates if any of them resolve to a member function.
+namespace TestOvlMatchingIgnoresImplicitObject {
+struct U;
+struct T {
+  std::strong_ordering operator<=>(U const &RHS) const;
+};
+struct U {
+  std::strong_ordering operator<=>(T const &RHS) const = delete;
+};
+
+struct V {
+  int x;
+};
+auto operator<=>(V const &LHS, V &&RHS) { // expected-note 4 {{candidate}}
+  return LHS.x <=> RHS.x;
+}
+auto operator<(V const &, V &&) { // expected-note {{candidate}}
+  return std::strong_equality::equal;
+}
+
+void test() {
+  // OK. selects T::operator<=>(U)
+  (void)(T{} < U{});
+  // expected-error@+1 {{use of overloaded operator '<' is ambiguous}}
+  (void)(V{} < V{});
+  // expected-error@+1 {{use of overloaded operator '<=>' is ambiguous}}
+  (void)(V{} <=> V{});
+}
+
+} // namespace TestOvlMatchingIgnoresImplicitObject
+
+namespace TestRewrittenTemplate {
+
+template 
+auto test(T const &LHS, T const &RHS) {
+  // expected-error@+1 {{invalid operands to binary expression ('const TestRewrittenTemplate::None'}}
+  return LHS < RHS;
+}
+struct None {};
+template auto test(None const &, None const &); // expected-note {{requested here}}
+
+struct Relational {};
+bool operator<(Relational, Relational);
+t

[PATCH] D45680: [C++2a] Implement operator<=> Part 2: Operator Rewritting and Overload Resolution.

2018-05-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146285.
EricWF added a comment.

- Update tests and improve diagnostics. Still more work to be done here though.


https://reviews.llvm.org/D45680

Files:
  include/clang/AST/ComparisonCategories.h
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/StmtNodes.td
  include/clang/Sema/Overload.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ComparisonCategories.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/cxx2a-compare.cpp
  test/SemaCXX/compare-cxx2a.cpp

Index: test/SemaCXX/compare-cxx2a.cpp
===
--- test/SemaCXX/compare-cxx2a.cpp
+++ test/SemaCXX/compare-cxx2a.cpp
@@ -292,20 +292,21 @@
 
 template 
 struct Tag {};
-// expected-note@+1 {{candidate}}
-Tag<0> operator<=>(EnumA, EnumA) {
-  return {};
+std::strong_ordering operator<=>(EnumA, EnumA) {
+  return std::strong_ordering::equal;
 }
-Tag<1> operator<=>(EnumA, EnumB) {
-  return {};
+// expected-note@+1 {{candidate function}},
+std::strong_ordering operator<=>(EnumA a, EnumB b) {
+  return ((int)a <=> (int)b);
 }
 
 void test_enum_ovl_provided() {
   auto r1 = (EnumA::A <=> EnumA::A);
-  ASSERT_EXPR_TYPE(r1, Tag<0>);
+  ASSERT_EXPR_TYPE(r1, std::strong_ordering);
   auto r2 = (EnumA::A <=> EnumB::B);
-  ASSERT_EXPR_TYPE(r2, Tag<1>);
-  (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}}
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+  (void)(EnumB::B <=> EnumA::A); // OK, chooses reverse order synthesized candidate.
+  (void)(EnumB::B <=> EnumC::C); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumC')}}
 }
 
 void enum_float_test() {
@@ -421,3 +422,132 @@
 }
 
 } // namespace ComplexTest
+
+namespace TestRewritting {
+
+struct T {
+  int x;
+  // expected-note@+1 {{candidate}}
+  constexpr std::strong_ordering operator<=>(T y) const {
+return (x <=> y.x);
+  }
+};
+
+struct U {
+  int x;
+  // FIXME(EricWF)
+  // expected-note@+1 {{return type cannot be used as an operand to the reversed rewritten comparison operator}}
+  constexpr std::strong_equality operator<=>(T y) const {
+if (x == y.x)
+  return std::strong_equality::equal;
+return std::strong_equality::nonequal;
+  }
+};
+
+struct X { int x; };
+struct Y { int x; };
+template 
+struct Tag {};
+
+// expected-note@+2 {{candidate function (rewritten operator) not viable: no known conversion from 'TestRewritting::T' to 'TestRewritting::X' for 1st argument}}
+// expected-note@+1 {{candidate function (reversed rewritten operator) not viable: no known conversion from 'TestRewritting::U' to 'TestRewritting::X' for 1st argument}}
+Tag<0> operator<=>(X, Y) {
+  return {};
+}
+
+// expected-note@+2 {{candidate function (rewritten operator) not viable: no known conversion from 'TestRewritting::T' to 'TestRewritting::Y' for 1st argument}}
+// expected-note@+1 {{candidate function (reversed rewritten operator) not viable: no known conversion from 'TestRewritting::U' to 'TestRewritting::Y' for 1st argument}}
+constexpr auto operator<=>(Y y, X x) {
+  return y.x <=> x.x;
+}
+
+void foo() {
+  T t{42};
+  T t2{0};
+  U u{101};
+  auto r1 = (t <=> u);
+  ASSERT_EXPR_TYPE(r1, std::strong_equality);
+  auto r2 = (t <=> t2);
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+
+  auto r3 = t == u;
+  ASSERT_EXPR_TYPE(r3, bool);
+
+  (void)(t < u); // expected-error {{invalid operands to binary expression ('TestRewritting::T' and 'TestRewritting::U')}}
+
+  constexpr X x{1};
+  constexpr Y y{2};
+  constexpr auto r4 = (y < x);
+  static_assert(r4 == false);
+  constexpr auto r5 = (x < y);
+  static_assert(r5 == true);
+}
+
+} // namespace TestRewritting
+
+// The implicit object parameter is not considered when performing partial
+// ordering. That makes the reverse synthesized candidates ambiguous with the
+// rewritten candidates if any of them resolve to a member function.
+namespace TestOvlMatchingIgnoresImplicitObject {
+struct U;
+struct T {
+  std::strong_ordering operator<=>(U const &RHS) const;
+};
+struct U {
+  std::strong_ordering operator<=>(T const &RHS) const = delete;
+};
+
+struct V {
+  int x;
+};
+auto operator<=>(V const &LHS, V &&RHS) { // expected-note 4 {{candidate}}
+  return LHS.x <=> RHS.x;
+}
+auto operator<(V const &, V &&) { // expected

[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146467.
EricWF added a comment.

@rsmith How does this look?

Turns out we have to fully parse the diagnostic text in order to substitute 
modifier indexes, which is a bit of a complication. This patch does exactly 
that.

There is still some work done to produce useful error messages when the 
substitution is ill-formed, but hopefully the design of this patch is, in 
general, OK>


https://reviews.llvm.org/D46740

Files:
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,14 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Regex.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -441,6 +443,654 @@
   }
 }
 
+namespace {
+enum PieceKind {
+  MultiPieceClass,
+  TextPieceClass,
+  PlaceholderPieceClass,
+  SelectPieceClass,
+  DiffPieceClass,
+  SubstitutionPieceClass,
+};
+
+struct DiagText;
+
+enum ModifierType {
+  MT_Unknown,
+  MT_Placeholder,
+  MT_Select,
+  MT_Sub,
+  MT_Plural,
+  MT_Diff,
+  MT_Ordinal,
+  MT_S,
+  MT_Q,
+  MT_ObjCClass,
+  MT_ObjCInstance,
+};
+
+static StringRef getModifierName(ModifierType MT) {
+  switch (MT) {
+  case MT_Select:
+return "select";
+  case MT_Sub:
+return "sub";
+  case MT_Diff:
+return "diff";
+  case MT_Plural:
+return "plural";
+  case MT_Ordinal:
+return "ordinal";
+  case MT_S:
+return "s";
+  case MT_Q:
+return "q";
+  case MT_Placeholder:
+return "";
+  case MT_ObjCClass:
+return "objcclass";
+  case MT_ObjCInstance:
+return "objcinstance";
+  case MT_Unknown:
+return "<>";
+  }
+}
+
+struct Piece {
+  // This type and its derived classes are move-only.
+  Piece(PieceKind Kind) : ClassKind(Kind) {}
+  Piece(Piece const &O) = delete;
+  Piece &operator=(Piece const &) = delete;
+  virtual ~Piece() {}
+
+  PieceKind getPieceClass() const { return ClassKind; }
+  static bool classof(const Piece *) { return true; }
+
+private:
+  PieceKind ClassKind;
+};
+
+struct MultiPiece : Piece {
+  MultiPiece() : Piece(MultiPieceClass) {}
+  MultiPiece(std::vector Pieces)
+  : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
+
+  std::vector Pieces;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == MultiPieceClass;
+  }
+};
+
+struct TextPiece : Piece {
+  StringRef Role;
+  std::string Text;
+  TextPiece(StringRef Text, StringRef Role = "")
+  : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == TextPieceClass;
+  }
+};
+
+struct PlaceholderPiece : Piece {
+  ModifierType Kind;
+  int Index;
+  PlaceholderPiece(ModifierType Kind, int Index)
+  : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PlaceholderPieceClass;
+  }
+};
+
+struct SelectPiece : Piece {
+  SelectPiece(ModifierType Kind) : Piece(SelectPieceClass), Kind(Kind) {}
+
+  ModifierType Kind;
+  std::vector Options;
+  unsigned Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SelectPieceClass;
+  }
+};
+
+struct DiffPiece : Piece {
+  DiffPiece() : Piece(DiffPieceClass) {}
+
+  Piece *Options[2] = {};
+  unsigned Indexes[2] = {};
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == DiffPieceClass;
+  }
+};
+
+struct SubstitutionPiece : Piece {
+  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
+
+  std::string Name;
+  std::vector Modifiers;
+  Piece *Substitution = nullptr;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SubstitutionPieceClass;
+  }
+};
+
+/// Diagnostic text, parsed into pieces.
+struct DiagText {
+private:
+  friend struct DiagnosticTextBuilder;
+  std::vector AllocatedPieces;
+  Piece *Root = nullptr;
+
+  template  T *create(Args &&... args) {
+static_assert(std::is_base_of::value, "must be piece");
+T *Mem = new T(std::forward(args)...);
+AllocatedPieces.push_back(Mem);
+return Mem;
+  }
+
+  DiagText() {}
+  Piece *parseDiagText(StringRef &Text, bool Nested = false);
+
+  DiagText(StringRef Text) : Root(nullptr) { Root = parseDi

[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added inline comments.



Comment at: test/TableGen/text-substitution.td:9
+
+// CHECK: AHHH
+def AGGG : Warning<"%select{one|two}0 is OK">, InGroup;

This test TBD. The `emit-diag-docs.td` test should hit all the major cases.


https://reviews.llvm.org/D46740



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


[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146470.
EricWF added a comment.

- Update tests.

The last thing I want to tackle is improving parsing errors to at least name 
the diagnostic being parsed. Naming *why* it's invalid if we don't provide its 
name.


https://reviews.llvm.org/D46740

Files:
  include/clang/Basic/Diagnostic.td
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,14 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Regex.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -441,6 +443,717 @@
   }
 }
 
+namespace {
+enum PieceKind {
+  MultiPieceClass,
+  TextPieceClass,
+  PlaceholderPieceClass,
+  SelectPieceClass,
+  PluralPieceClass,
+  DiffPieceClass,
+  SubstitutionPieceClass,
+};
+
+enum ModifierType {
+  MT_Unknown,
+  MT_Placeholder,
+  MT_Select,
+  MT_Sub,
+  MT_Plural,
+  MT_Diff,
+  MT_Ordinal,
+  MT_S,
+  MT_Q,
+  MT_ObjCClass,
+  MT_ObjCInstance,
+};
+
+static StringRef getModifierName(ModifierType MT) {
+  switch (MT) {
+  case MT_Select:
+return "select";
+  case MT_Sub:
+return "sub";
+  case MT_Diff:
+return "diff";
+  case MT_Plural:
+return "plural";
+  case MT_Ordinal:
+return "ordinal";
+  case MT_S:
+return "s";
+  case MT_Q:
+return "q";
+  case MT_Placeholder:
+return "";
+  case MT_ObjCClass:
+return "objcclass";
+  case MT_ObjCInstance:
+return "objcinstance";
+  case MT_Unknown:
+return "<>";
+  }
+}
+
+struct Piece {
+  // This type and its derived classes are move-only.
+  Piece(PieceKind Kind) : ClassKind(Kind) {}
+  Piece(Piece const &O) = delete;
+  Piece &operator=(Piece const &) = delete;
+  virtual ~Piece() {}
+
+  PieceKind getPieceClass() const { return ClassKind; }
+  static bool classof(const Piece *) { return true; }
+
+private:
+  PieceKind ClassKind;
+};
+
+struct MultiPiece : Piece {
+  MultiPiece() : Piece(MultiPieceClass) {}
+  MultiPiece(std::vector Pieces)
+  : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
+
+  std::vector Pieces;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == MultiPieceClass;
+  }
+};
+
+struct TextPiece : Piece {
+  StringRef Role;
+  std::string Text;
+  TextPiece(StringRef Text, StringRef Role = "")
+  : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == TextPieceClass;
+  }
+};
+
+struct PlaceholderPiece : Piece {
+  ModifierType Kind;
+  int Index;
+  PlaceholderPiece(ModifierType Kind, int Index)
+  : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PlaceholderPieceClass;
+  }
+};
+
+struct SelectPiece : Piece {
+protected:
+  SelectPiece(PieceKind Kind, ModifierType ModKind)
+  : Piece(Kind), ModKind(ModKind) {}
+
+public:
+  SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
+
+  ModifierType ModKind;
+  std::vector Options;
+  unsigned Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SelectPieceClass ||
+   P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct PluralPiece : SelectPiece {
+  PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
+
+  std::vector OptionPrefixes;
+  unsigned Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct DiffPiece : Piece {
+  DiffPiece() : Piece(DiffPieceClass) {}
+
+  Piece *Options[2] = {};
+  unsigned Indexes[2] = {};
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == DiffPieceClass;
+  }
+};
+
+struct SubstitutionPiece : Piece {
+  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
+
+  std::string Name;
+  std::vector Modifiers;
+  Piece *Substitution = nullptr;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SubstitutionPieceClass;
+  }
+};
+
+/// Diagnostic text, parsed into pieces.
+
+
+struct DiagnosticTextBuilder {
+  DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
+  DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
+
+  DiagnosticTextBuilder(RecordKeeper &Records) {
+for (auto *S : Reco

[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

@rsmith Can select indexes be negative? What's the correct type to represent 
them? Existing code seems to use `int`, but the LLVM style seems to suggest 
`unsigned` is more appropriate.




Comment at: utils/TableGen/ClangDiagnosticsEmitter.cpp:591
+  std::vector Modifiers;
+  Piece *Substitution = nullptr;
+

This is unused. Removing.


https://reviews.llvm.org/D46740



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


[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146491.
EricWF edited the summary of this revision.
EricWF added a comment.

- Get argument renumbering work as @rsmith requested.
- Make the changes to existing diagnostics whitespace correct.
- Cleanup `DiagnosticSemaKinds.td` and `SemaOverload.cpp` to take advantage of 
this change.

@rsmith, @rjmccall: This change set is a lot larger now. Is it appropriate to 
commit the Sema cleanup with this patch?


https://reviews.llvm.org/D46740

Files:
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Basic/Diagnostic.cpp
  lib/Sema/SemaOverload.cpp
  test/SemaCXX/anonymous-struct.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,13 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -441,6 +442,722 @@
   }
 }
 
+namespace {
+enum PieceKind {
+  MultiPieceClass,
+  TextPieceClass,
+  PlaceholderPieceClass,
+  SelectPieceClass,
+  PluralPieceClass,
+  DiffPieceClass,
+  SubstitutionPieceClass,
+};
+
+enum ModifierType {
+  MT_Unknown,
+  MT_Placeholder,
+  MT_Select,
+  MT_Sub,
+  MT_Plural,
+  MT_Diff,
+  MT_Ordinal,
+  MT_S,
+  MT_Q,
+  MT_ObjCClass,
+  MT_ObjCInstance,
+};
+
+static StringRef getModifierName(ModifierType MT) {
+  switch (MT) {
+  case MT_Select:
+return "select";
+  case MT_Sub:
+return "sub";
+  case MT_Diff:
+return "diff";
+  case MT_Plural:
+return "plural";
+  case MT_Ordinal:
+return "ordinal";
+  case MT_S:
+return "s";
+  case MT_Q:
+return "q";
+  case MT_Placeholder:
+return "";
+  case MT_ObjCClass:
+return "objcclass";
+  case MT_ObjCInstance:
+return "objcinstance";
+  case MT_Unknown:
+llvm_unreachable("invalid modifier type");
+  }
+}
+
+struct Piece {
+  // This type and its derived classes are move-only.
+  Piece(PieceKind Kind) : ClassKind(Kind) {}
+  Piece(Piece const &O) = delete;
+  Piece &operator=(Piece const &) = delete;
+  virtual ~Piece() {}
+
+  PieceKind getPieceClass() const { return ClassKind; }
+  static bool classof(const Piece *) { return true; }
+
+private:
+  PieceKind ClassKind;
+};
+
+struct MultiPiece : Piece {
+  MultiPiece() : Piece(MultiPieceClass) {}
+  MultiPiece(std::vector Pieces)
+  : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
+
+  std::vector Pieces;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == MultiPieceClass;
+  }
+};
+
+struct TextPiece : Piece {
+  StringRef Role;
+  std::string Text;
+  TextPiece(StringRef Text, StringRef Role = "")
+  : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == TextPieceClass;
+  }
+};
+
+struct PlaceholderPiece : Piece {
+  ModifierType Kind;
+  int Index;
+  PlaceholderPiece(ModifierType Kind, int Index)
+  : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PlaceholderPieceClass;
+  }
+};
+
+struct SelectPiece : Piece {
+protected:
+  SelectPiece(PieceKind Kind, ModifierType ModKind)
+  : Piece(Kind), ModKind(ModKind) {}
+
+public:
+  SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
+
+  ModifierType ModKind;
+  std::vector Options;
+  unsigned Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SelectPieceClass ||
+   P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct PluralPiece : SelectPiece {
+  PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
+
+  std::vector OptionPrefixes;
+  unsigned Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct DiffPiece : Piece {
+  DiffPiece() : Piece(DiffPieceClass) {}
+
+  Piece *Options[2] = {};
+  unsigned Indexes[2] = {};
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == DiffPieceClass;
+  }
+};
+
+struct SubstitutionPiece : Piece {
+  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
+
+  std::string Name;
+  std::vector Modifiers;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == Substit

[PATCH] D23041: Un-XFAIL GCC atomics.align

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

OK, here's what I would do:

(1) Split the vector, nullptr, and other weirdly failing tests into their own 
files.
(2) In each file, use `defined(TEST_COMPILER_GCC) && __GXX_ABI_VERSION > 1006` 
(or w/e version is broken) to define a macro when the test is expected to fail.
(3) Either `ifdef` out failing tests, or change the assertion to expect 
failure. The latter is probably preferable as it will allow us to detect if 
they test ever starts unexpectedly passing.
(4) Add tests for GCC with different `fabi-version` options. I would make these 
separate test files which wrap the actual test their targeting. For example:

  //
  // This file is dual licensed under the MIT and the University of Illinois 
Open
  // Source Licenses. See LICENSE.TXT for details.
  //
  
//===--===//
  //
  // REQUIRES: gcc, libatomic
  // UNSUPPORTED: libcpp-has-no-threads, c++98, c++03
  //
  // RUN: %cxx -o %t.one.exe %s %all_flags -latomic -fabi-version=2 && 
%t.one.exe
  // RUN: %cxx -o %t.two.exe %s %all_flags -latomic -fabi-version=6 && 
%t.two.exe
  // RUN: %cxx -o %t.three.exe %s %all_flags -latomic -fabi-version=9 && 
%t.three.exe
  
  #include "align-vector-types.sh.cpp"

How does that sound?


https://reviews.llvm.org/D23041



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


[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146495.
EricWF added a comment.

Document `%sub` in `InternalsManual.rst`


https://reviews.llvm.org/D46740

Files:
  docs/InternalsManual.rst
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Basic/Diagnostic.cpp
  lib/Sema/SemaOverload.cpp
  test/SemaCXX/anonymous-struct.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,13 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -441,6 +442,722 @@
   }
 }
 
+namespace {
+enum PieceKind {
+  MultiPieceClass,
+  TextPieceClass,
+  PlaceholderPieceClass,
+  SelectPieceClass,
+  PluralPieceClass,
+  DiffPieceClass,
+  SubstitutionPieceClass,
+};
+
+enum ModifierType {
+  MT_Unknown,
+  MT_Placeholder,
+  MT_Select,
+  MT_Sub,
+  MT_Plural,
+  MT_Diff,
+  MT_Ordinal,
+  MT_S,
+  MT_Q,
+  MT_ObjCClass,
+  MT_ObjCInstance,
+};
+
+static StringRef getModifierName(ModifierType MT) {
+  switch (MT) {
+  case MT_Select:
+return "select";
+  case MT_Sub:
+return "sub";
+  case MT_Diff:
+return "diff";
+  case MT_Plural:
+return "plural";
+  case MT_Ordinal:
+return "ordinal";
+  case MT_S:
+return "s";
+  case MT_Q:
+return "q";
+  case MT_Placeholder:
+return "";
+  case MT_ObjCClass:
+return "objcclass";
+  case MT_ObjCInstance:
+return "objcinstance";
+  case MT_Unknown:
+llvm_unreachable("invalid modifier type");
+  }
+}
+
+struct Piece {
+  // This type and its derived classes are move-only.
+  Piece(PieceKind Kind) : ClassKind(Kind) {}
+  Piece(Piece const &O) = delete;
+  Piece &operator=(Piece const &) = delete;
+  virtual ~Piece() {}
+
+  PieceKind getPieceClass() const { return ClassKind; }
+  static bool classof(const Piece *) { return true; }
+
+private:
+  PieceKind ClassKind;
+};
+
+struct MultiPiece : Piece {
+  MultiPiece() : Piece(MultiPieceClass) {}
+  MultiPiece(std::vector Pieces)
+  : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
+
+  std::vector Pieces;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == MultiPieceClass;
+  }
+};
+
+struct TextPiece : Piece {
+  StringRef Role;
+  std::string Text;
+  TextPiece(StringRef Text, StringRef Role = "")
+  : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == TextPieceClass;
+  }
+};
+
+struct PlaceholderPiece : Piece {
+  ModifierType Kind;
+  int Index;
+  PlaceholderPiece(ModifierType Kind, int Index)
+  : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PlaceholderPieceClass;
+  }
+};
+
+struct SelectPiece : Piece {
+protected:
+  SelectPiece(PieceKind Kind, ModifierType ModKind)
+  : Piece(Kind), ModKind(ModKind) {}
+
+public:
+  SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
+
+  ModifierType ModKind;
+  std::vector Options;
+  unsigned Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SelectPieceClass ||
+   P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct PluralPiece : SelectPiece {
+  PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
+
+  std::vector OptionPrefixes;
+  unsigned Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct DiffPiece : Piece {
+  DiffPiece() : Piece(DiffPieceClass) {}
+
+  Piece *Options[2] = {};
+  unsigned Indexes[2] = {};
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == DiffPieceClass;
+  }
+};
+
+struct SubstitutionPiece : Piece {
+  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
+
+  std::string Name;
+  std::vector Modifiers;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SubstitutionPieceClass;
+  }
+};
+
+/// Diagnostic text, parsed into pieces.
+
+
+struct DiagnosticTextBuilder {
+  DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
+  DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
+
+  DiagnosticTextBuilder(RecordKeeper &Records) {
+/

[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 4 inline comments as done.
EricWF added a comment.

In https://reviews.llvm.org/D46740#1097014, @rsmith wrote:

> Thanks, this is great.
>
> In https://reviews.llvm.org/D46740#1096859, @EricWF wrote:
>
> > Turns out we have to fully parse the diagnostic text in order to substitute 
> > modifier indexes, which is a bit of a complication. This patch does exactly 
> > that.
>
>
> I like that you were able to reuse the existing parsing code for 
> documentation generation here.


With heavy modifications  :-)




Comment at: docs/InternalsManual.rst:341-342
+  ``"candidate %select{function|constructor}3%select{| template| %1}2 not 
viable"``.
+Class:
+  ``Integers``
+Description:

rsmith wrote:
> I don't think "Class:" makes sense here, since what this specifier consumes 
> depends on its replacement string. "Class: varies" or similar might work, but 
> maybe just drop it?
Dropping it seems clearer.



Comment at: include/clang/Basic/DiagnosticSemaKinds.td:3526-3544
 def note_ovl_candidate : Note<"candidate "
 "%select{function|function|constructor|"
-"function |function |constructor |"
 "is the implicit default constructor|"
 "is the implicit copy constructor|"
 "is the implicit move constructor|"
 "is the implicit copy assignment operator|"
 "is the implicit move assignment operator|"

rsmith wrote:
> Is there a reason this one wasn't changed to use `%sub`?
It refers to implicit special members differently ("is the implicit default 
constructor" -> "constructor (the implicit default constructor"). I think I 
mistakenly thought transforming it would be grammatically incorrect. But 
looking further it seems fine.



https://reviews.llvm.org/D46740



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


[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

In https://reviews.llvm.org/D46740#1097014, @rsmith wrote:

> Thanks, this is great.
>
> In https://reviews.llvm.org/D46740#1096859, @EricWF wrote:
>
> > Turns out we have to fully parse the diagnostic text in order to substitute 
> > modifier indexes, which is a bit of a complication. This patch does exactly 
> > that.
>
>
> I like that you were able to reuse the existing parsing code for 
> documentation generation here.


With heavy modifications  :-)


https://reviews.llvm.org/D46740



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


[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146498.
EricWF marked 2 inline comments as done.
EricWF added a comment.

Address @rsmiths comments.

- Prefer `int` to `unsigned`.
- Substitute `note_ovl_candidate`.
- Fix issues in docs.


https://reviews.llvm.org/D46740

Files:
  docs/InternalsManual.rst
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Basic/Diagnostic.cpp
  lib/Sema/SemaOverload.cpp
  test/SemaCXX/anonymous-struct.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,13 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -441,6 +442,722 @@
   }
 }
 
+namespace {
+enum PieceKind {
+  MultiPieceClass,
+  TextPieceClass,
+  PlaceholderPieceClass,
+  SelectPieceClass,
+  PluralPieceClass,
+  DiffPieceClass,
+  SubstitutionPieceClass,
+};
+
+enum ModifierType {
+  MT_Unknown,
+  MT_Placeholder,
+  MT_Select,
+  MT_Sub,
+  MT_Plural,
+  MT_Diff,
+  MT_Ordinal,
+  MT_S,
+  MT_Q,
+  MT_ObjCClass,
+  MT_ObjCInstance,
+};
+
+static StringRef getModifierName(ModifierType MT) {
+  switch (MT) {
+  case MT_Select:
+return "select";
+  case MT_Sub:
+return "sub";
+  case MT_Diff:
+return "diff";
+  case MT_Plural:
+return "plural";
+  case MT_Ordinal:
+return "ordinal";
+  case MT_S:
+return "s";
+  case MT_Q:
+return "q";
+  case MT_Placeholder:
+return "";
+  case MT_ObjCClass:
+return "objcclass";
+  case MT_ObjCInstance:
+return "objcinstance";
+  case MT_Unknown:
+llvm_unreachable("invalid modifier type");
+  }
+}
+
+struct Piece {
+  // This type and its derived classes are move-only.
+  Piece(PieceKind Kind) : ClassKind(Kind) {}
+  Piece(Piece const &O) = delete;
+  Piece &operator=(Piece const &) = delete;
+  virtual ~Piece() {}
+
+  PieceKind getPieceClass() const { return ClassKind; }
+  static bool classof(const Piece *) { return true; }
+
+private:
+  PieceKind ClassKind;
+};
+
+struct MultiPiece : Piece {
+  MultiPiece() : Piece(MultiPieceClass) {}
+  MultiPiece(std::vector Pieces)
+  : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
+
+  std::vector Pieces;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == MultiPieceClass;
+  }
+};
+
+struct TextPiece : Piece {
+  StringRef Role;
+  std::string Text;
+  TextPiece(StringRef Text, StringRef Role = "")
+  : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == TextPieceClass;
+  }
+};
+
+struct PlaceholderPiece : Piece {
+  ModifierType Kind;
+  int Index;
+  PlaceholderPiece(ModifierType Kind, int Index)
+  : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PlaceholderPieceClass;
+  }
+};
+
+struct SelectPiece : Piece {
+protected:
+  SelectPiece(PieceKind Kind, ModifierType ModKind)
+  : Piece(Kind), ModKind(ModKind) {}
+
+public:
+  SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
+
+  ModifierType ModKind;
+  std::vector Options;
+  int Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SelectPieceClass ||
+   P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct PluralPiece : SelectPiece {
+  PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
+
+  std::vector OptionPrefixes;
+  int Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct DiffPiece : Piece {
+  DiffPiece() : Piece(DiffPieceClass) {}
+
+  Piece *Options[2] = {};
+  int Indexes[2] = {};
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == DiffPieceClass;
+  }
+};
+
+struct SubstitutionPiece : Piece {
+  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
+
+  std::string Name;
+  std::vector Modifiers;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SubstitutionPieceClass;
+  }
+};
+
+/// Diagnostic text, parsed into pieces.
+
+
+struct DiagnosticTextBuilder {
+  DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
+  DiagnosticTextBuilder &operator=

[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-13 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 146508.
EricWF marked an inline comment as done.
EricWF added a comment.

Misc cleanups.

- proof read and correct documentation.


https://reviews.llvm.org/D46740

Files:
  docs/InternalsManual.rst
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Basic/Diagnostic.cpp
  lib/Sema/SemaOverload.cpp
  test/SemaCXX/anonymous-struct.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,13 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -441,6 +442,722 @@
   }
 }
 
+namespace {
+enum PieceKind {
+  MultiPieceClass,
+  TextPieceClass,
+  PlaceholderPieceClass,
+  SelectPieceClass,
+  PluralPieceClass,
+  DiffPieceClass,
+  SubstitutionPieceClass,
+};
+
+enum ModifierType {
+  MT_Unknown,
+  MT_Placeholder,
+  MT_Select,
+  MT_Sub,
+  MT_Plural,
+  MT_Diff,
+  MT_Ordinal,
+  MT_S,
+  MT_Q,
+  MT_ObjCClass,
+  MT_ObjCInstance,
+};
+
+static StringRef getModifierName(ModifierType MT) {
+  switch (MT) {
+  case MT_Select:
+return "select";
+  case MT_Sub:
+return "sub";
+  case MT_Diff:
+return "diff";
+  case MT_Plural:
+return "plural";
+  case MT_Ordinal:
+return "ordinal";
+  case MT_S:
+return "s";
+  case MT_Q:
+return "q";
+  case MT_Placeholder:
+return "";
+  case MT_ObjCClass:
+return "objcclass";
+  case MT_ObjCInstance:
+return "objcinstance";
+  case MT_Unknown:
+llvm_unreachable("invalid modifier type");
+  }
+}
+
+struct Piece {
+  // This type and its derived classes are move-only.
+  Piece(PieceKind Kind) : ClassKind(Kind) {}
+  Piece(Piece const &O) = delete;
+  Piece &operator=(Piece const &) = delete;
+  virtual ~Piece() {}
+
+  PieceKind getPieceClass() const { return ClassKind; }
+  static bool classof(const Piece *) { return true; }
+
+private:
+  PieceKind ClassKind;
+};
+
+struct MultiPiece : Piece {
+  MultiPiece() : Piece(MultiPieceClass) {}
+  MultiPiece(std::vector Pieces)
+  : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
+
+  std::vector Pieces;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == MultiPieceClass;
+  }
+};
+
+struct TextPiece : Piece {
+  StringRef Role;
+  std::string Text;
+  TextPiece(StringRef Text, StringRef Role = "")
+  : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == TextPieceClass;
+  }
+};
+
+struct PlaceholderPiece : Piece {
+  ModifierType Kind;
+  int Index;
+  PlaceholderPiece(ModifierType Kind, int Index)
+  : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PlaceholderPieceClass;
+  }
+};
+
+struct SelectPiece : Piece {
+protected:
+  SelectPiece(PieceKind Kind, ModifierType ModKind)
+  : Piece(Kind), ModKind(ModKind) {}
+
+public:
+  SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
+
+  ModifierType ModKind;
+  std::vector Options;
+  int Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SelectPieceClass ||
+   P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct PluralPiece : SelectPiece {
+  PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
+
+  std::vector OptionPrefixes;
+  int Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct DiffPiece : Piece {
+  DiffPiece() : Piece(DiffPieceClass) {}
+
+  Piece *Options[2] = {};
+  int Indexes[2] = {};
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == DiffPieceClass;
+  }
+};
+
+struct SubstitutionPiece : Piece {
+  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
+
+  std::string Name;
+  std::vector Modifiers;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SubstitutionPieceClass;
+  }
+};
+
+/// Diagnostic text, parsed into pieces.
+
+
+struct DiagnosticTextBuilder {
+  DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
+  DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
+
+  DiagnosticTe

[PATCH] D46964: Implement class deduction guides for `std::array`

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added inline comments.
This revision is now accepted and ready to land.



Comment at: include/array:75
 
+  template 
+array(T, U...) -> array;

Don't we normally comment `// C++17` or similar for new features in the 
synopsis?



Comment at: include/array:361
+#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
+template && ...), void>::type

The `is same` clause is a requirement, not a SFINAE constraint. Should this be 
a hard error? Should we really SFINAE it?



Comment at: test/std/containers/sequences/array/array.cons/deduct.fail.cpp:12
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// XFAIL: libcpp-no-deduction-guides
+

This should be `UNSUPPORTED`. We don't expect this test to ever pass without 
deduction guides.



Comment at: test/std/containers/sequences/array/array.cons/deduct.pass.cpp:12
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// XFAIL: libcpp-no-deduction-guides
+

`UNSUPPORTED`


https://reviews.llvm.org/D46964



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


[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 2 inline comments as done.
EricWF added inline comments.



Comment at: utils/TableGen/ClangDiagnosticsEmitter.cpp:514
+  std::vector Diags = Records.getAllDerivedDefinitions("Diagnostic");
+  llvm::for_each(Diags, [&](Record *R) { substituteDiagText(R, SubsMap); });
 

rjmccall wrote:
> I see why this has to be done separately, I think, but it should at least go 
> in a helper function.
> 
> Also, please check for substitution-name conflicts.
@rjmccall By substitution name conflicts do you mean substitution names which 
conflict with diagnostic names?


https://reviews.llvm.org/D46740



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


[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 147581.
EricWF marked an inline comment as done.
EricWF added a comment.

- Add error if a substitution and a diagnostic share the same name.

Any final comments on this?


https://reviews.llvm.org/D46740

Files:
  docs/InternalsManual.rst
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Basic/Diagnostic.cpp
  lib/Sema/SemaOverload.cpp
  test/SemaCXX/anonymous-struct.cpp
  test/SemaCXX/cxx1y-generic-lambdas.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,13 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -441,6 +442,733 @@
   }
 }
 
+namespace {
+enum PieceKind {
+  MultiPieceClass,
+  TextPieceClass,
+  PlaceholderPieceClass,
+  SelectPieceClass,
+  PluralPieceClass,
+  DiffPieceClass,
+  SubstitutionPieceClass,
+};
+
+enum ModifierType {
+  MT_Unknown,
+  MT_Placeholder,
+  MT_Select,
+  MT_Sub,
+  MT_Plural,
+  MT_Diff,
+  MT_Ordinal,
+  MT_S,
+  MT_Q,
+  MT_ObjCClass,
+  MT_ObjCInstance,
+};
+
+static StringRef getModifierName(ModifierType MT) {
+  switch (MT) {
+  case MT_Select:
+return "select";
+  case MT_Sub:
+return "sub";
+  case MT_Diff:
+return "diff";
+  case MT_Plural:
+return "plural";
+  case MT_Ordinal:
+return "ordinal";
+  case MT_S:
+return "s";
+  case MT_Q:
+return "q";
+  case MT_Placeholder:
+return "";
+  case MT_ObjCClass:
+return "objcclass";
+  case MT_ObjCInstance:
+return "objcinstance";
+  case MT_Unknown:
+llvm_unreachable("invalid modifier type");
+  }
+}
+
+struct Piece {
+  // This type and its derived classes are move-only.
+  Piece(PieceKind Kind) : ClassKind(Kind) {}
+  Piece(Piece const &O) = delete;
+  Piece &operator=(Piece const &) = delete;
+  virtual ~Piece() {}
+
+  PieceKind getPieceClass() const { return ClassKind; }
+  static bool classof(const Piece *) { return true; }
+
+private:
+  PieceKind ClassKind;
+};
+
+struct MultiPiece : Piece {
+  MultiPiece() : Piece(MultiPieceClass) {}
+  MultiPiece(std::vector Pieces)
+  : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
+
+  std::vector Pieces;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == MultiPieceClass;
+  }
+};
+
+struct TextPiece : Piece {
+  StringRef Role;
+  std::string Text;
+  TextPiece(StringRef Text, StringRef Role = "")
+  : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == TextPieceClass;
+  }
+};
+
+struct PlaceholderPiece : Piece {
+  ModifierType Kind;
+  int Index;
+  PlaceholderPiece(ModifierType Kind, int Index)
+  : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PlaceholderPieceClass;
+  }
+};
+
+struct SelectPiece : Piece {
+protected:
+  SelectPiece(PieceKind Kind, ModifierType ModKind)
+  : Piece(Kind), ModKind(ModKind) {}
+
+public:
+  SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
+
+  ModifierType ModKind;
+  std::vector Options;
+  int Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SelectPieceClass ||
+   P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct PluralPiece : SelectPiece {
+  PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
+
+  std::vector OptionPrefixes;
+  int Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct DiffPiece : Piece {
+  DiffPiece() : Piece(DiffPieceClass) {}
+
+  Piece *Options[2] = {};
+  int Indexes[2] = {};
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == DiffPieceClass;
+  }
+};
+
+struct SubstitutionPiece : Piece {
+  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
+
+  std::string Name;
+  std::vector Modifiers;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SubstitutionPieceClass;
+  }
+};
+
+/// Diagnostic text, parsed into pieces.
+
+
+struct DiagnosticTextBuilder {
+  DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
+  Diagnosti

[PATCH] D47092: downgrade strong type info names to weak_odr linkage

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

Sorry @rsmith, I was just about to tackle this.


Repository:
  rC Clang

https://reviews.llvm.org/D47092



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


[PATCH] D47090: Implement C++17 .

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

I would prefer if we completed `` (according to 
the current standard, not the LFTS spec), and then moved it.

Would you be willing to do that instead?


Repository:
  rCXX libc++

https://reviews.llvm.org/D47090



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 147639.
EricWF added a comment.

- Handle array types as requested.

- Attempt to handle incomplete class types. They are always considered in need 
of laundering. Including class templates who's instantiation hasn't been forced 
yet. @rsmith is this the correct thing to do?


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,72 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp, int (&Arr)[5]) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder(&fnp);
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder(Arr);
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *&fp,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(&const_int);
+static_assert(&const_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(&const_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(&i); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int &i) {
+  return (__builtin_launder(&i) == &i);
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `&i` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -249,6 +249,24 @@
 return buf;
 }
 
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_lau

[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 147640.
EricWF added a comment.

- Remove changes to Sema, and overload resolution diagnostics. Only change the 
special member function diagnostics as an example.

If there are no further comments, I'll commit this once I've run the test suite.


https://reviews.llvm.org/D46740

Files:
  docs/InternalsManual.rst
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  test/SemaCXX/anonymous-struct.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: utils/TableGen/ClangDiagnosticsEmitter.cpp
===
--- utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -14,12 +14,13 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -441,6 +442,733 @@
   }
 }
 
+namespace {
+enum PieceKind {
+  MultiPieceClass,
+  TextPieceClass,
+  PlaceholderPieceClass,
+  SelectPieceClass,
+  PluralPieceClass,
+  DiffPieceClass,
+  SubstitutionPieceClass,
+};
+
+enum ModifierType {
+  MT_Unknown,
+  MT_Placeholder,
+  MT_Select,
+  MT_Sub,
+  MT_Plural,
+  MT_Diff,
+  MT_Ordinal,
+  MT_S,
+  MT_Q,
+  MT_ObjCClass,
+  MT_ObjCInstance,
+};
+
+static StringRef getModifierName(ModifierType MT) {
+  switch (MT) {
+  case MT_Select:
+return "select";
+  case MT_Sub:
+return "sub";
+  case MT_Diff:
+return "diff";
+  case MT_Plural:
+return "plural";
+  case MT_Ordinal:
+return "ordinal";
+  case MT_S:
+return "s";
+  case MT_Q:
+return "q";
+  case MT_Placeholder:
+return "";
+  case MT_ObjCClass:
+return "objcclass";
+  case MT_ObjCInstance:
+return "objcinstance";
+  case MT_Unknown:
+llvm_unreachable("invalid modifier type");
+  }
+}
+
+struct Piece {
+  // This type and its derived classes are move-only.
+  Piece(PieceKind Kind) : ClassKind(Kind) {}
+  Piece(Piece const &O) = delete;
+  Piece &operator=(Piece const &) = delete;
+  virtual ~Piece() {}
+
+  PieceKind getPieceClass() const { return ClassKind; }
+  static bool classof(const Piece *) { return true; }
+
+private:
+  PieceKind ClassKind;
+};
+
+struct MultiPiece : Piece {
+  MultiPiece() : Piece(MultiPieceClass) {}
+  MultiPiece(std::vector Pieces)
+  : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
+
+  std::vector Pieces;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == MultiPieceClass;
+  }
+};
+
+struct TextPiece : Piece {
+  StringRef Role;
+  std::string Text;
+  TextPiece(StringRef Text, StringRef Role = "")
+  : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == TextPieceClass;
+  }
+};
+
+struct PlaceholderPiece : Piece {
+  ModifierType Kind;
+  int Index;
+  PlaceholderPiece(ModifierType Kind, int Index)
+  : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PlaceholderPieceClass;
+  }
+};
+
+struct SelectPiece : Piece {
+protected:
+  SelectPiece(PieceKind Kind, ModifierType ModKind)
+  : Piece(Kind), ModKind(ModKind) {}
+
+public:
+  SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
+
+  ModifierType ModKind;
+  std::vector Options;
+  int Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SelectPieceClass ||
+   P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct PluralPiece : SelectPiece {
+  PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
+
+  std::vector OptionPrefixes;
+  int Index;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == PluralPieceClass;
+  }
+};
+
+struct DiffPiece : Piece {
+  DiffPiece() : Piece(DiffPieceClass) {}
+
+  Piece *Options[2] = {};
+  int Indexes[2] = {};
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == DiffPieceClass;
+  }
+};
+
+struct SubstitutionPiece : Piece {
+  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
+
+  std::string Name;
+  std::vector Modifiers;
+
+  static bool classof(const Piece *P) {
+return P->getPieceClass() == SubstitutionPieceClass;
+  }
+};
+
+/// Diagnostic text, parsed into pieces.
+
+
+struct DiagnosticTextBuilder {
+  DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
+  DiagnosticTextBuilder &operato

[PATCH] D46740: [Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rC332799: [Clang Tablegen][RFC] Allow Early Textual 
Substitutions in `Diagnostic`… (authored by EricWF, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D46740

Files:
  docs/InternalsManual.rst
  include/clang/Basic/Diagnostic.td
  include/clang/Basic/DiagnosticSemaKinds.td
  test/SemaCXX/anonymous-struct.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/TableGen/DiagnosticBase.inc
  test/TableGen/DiagnosticDocs.inc
  test/TableGen/emit-diag-docs.td
  test/TableGen/text-substitution.td
  test/lit.cfg.py
  utils/TableGen/ClangDiagnosticsEmitter.cpp

Index: docs/InternalsManual.rst
===
--- docs/InternalsManual.rst
+++ docs/InternalsManual.rst
@@ -319,6 +319,32 @@
 repetitive diagnostics and/or have an idea for a useful formatter, please bring
 it up on the cfe-dev mailing list.
 
+**"sub" format**
+
+Example:
+  Given the following record definition of type ``TextSubstitution``:
+
+  .. code-block:: text
+
+def select_ovl_candidate : TextSubstitution<
+  "%select{function|constructor}0%select{| template| %2}1">;
+
+  which can be used as
+
+  .. code-block:: text
+
+def note_ovl_candidate : Note<
+  "candidate %sub{select_ovl_candidate}3,2,1 not viable">;
+
+  and will act as if it was written
+  ``"candidate %select{function|constructor}3%select{| template| %1}2 not viable"``.
+Description:
+  This format specifier is used to avoid repeating strings verbatim in multiple
+  diagnostics. The argument to ``%sub`` must name a ``TextSubstitution`` tblgen
+  record. The substitution must specify all arguments used by the substitution,
+  and the modifier indexes in the substitution are re-numbered accordingly. The
+  substituted text must itself be a valid format string before substitution.
+
 .. _internals-producing-diag:
 
 Producing the Diagnostic
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1622,13 +1622,16 @@
   "overrides of %0 in subclasses are not available in the "
   "%select{constructor|destructor}1 of %2">;
 
+def select_special_member_kind : TextSubstitution<
+  "%select{default constructor|copy constructor|move constructor|"
+  "copy assignment operator|move assignment operator|destructor}0">;
+
 def note_member_declared_at : Note<"member is declared here">;
 def note_ivar_decl : Note<"instance variable is declared here">;
 def note_bitfield_decl : Note<"bit-field is declared here">;
 def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
 def note_member_synthesized_at : Note<
-  "in implicit %select{default constructor|copy constructor|move constructor|"
-  "copy assignment operator|move assignment operator|destructor}0 for %1 "
+  "in implicit %sub{select_special_member_kind}0 for %1 "
   "first required here">;
 def err_missing_default_ctor : Error<
   "%select{constructor for %1 must explicitly initialize the|"
@@ -1641,12 +1644,10 @@
 
 def err_illegal_union_or_anon_struct_member : Error<
   "%select{anonymous struct|union}0 member %1 has a non-trivial "
-  "%select{constructor|copy constructor|move constructor|copy assignment "
-  "operator|move assignment operator|destructor}2">;
+  "%sub{select_special_member_kind}2">;
 def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning<
   "%select{anonymous struct|union}0 member %1 with a non-trivial "
-  "%select{constructor|copy constructor|move constructor|copy assignment "
-  "operator|move assignment operator|destructor}2 is incompatible with C++98">,
+  "%sub{select_special_member_kind}2 is incompatible with C++98">,
   InGroup, DefaultIgnore;
 
 def note_nontrivial_virtual_dtor : Note<
@@ -1665,8 +1666,7 @@
   "%select{base class|field|an object}0 of type %3">;
 def note_nontrivial_user_provided : Note<
   "because %select{base class of |field of |}0type %1 has a user-provided "
-  "%select{default constructor|copy constructor|move constructor|"
-  "copy assignment operator|move assignment operator|destructor}2">;
+  "%sub{select_special_member_kind}2">;
 def note_nontrivial_in_class_init : Note<
   "because field %0 has an initializer">;
 def note_nontrivial_param_type : Note<
@@ -1733,9 +1733,7 @@
 
 // C++ implicit special member functions
 def note_in_declaration_of_implicit_special_member : Note<
-  "while declaring the implicit "
-  "%select{default constructor|copy constructor|move constructor|"
-  "copy assignment operator|move assignment operator|destructor}1"
+  "while declaring the implicit %sub{select_special_member_kind}1"
   " for %0">;
 
 // C++ constructors
@@ -3837,13 +3835,7 @@
 "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from"
   

[PATCH] D47101: [Sema] Use %sub to cleanup overload diagnostics

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF created this revision.
EricWF added a reviewer: rsmith.

This patch adds the newly added `%sub` diagnostic modifier to cleanup 
repetition in the overload candidate diagnostics.

I think this should be good to go.

@rsmith: Some of the notes now emit `function template` where they only said 
`function` previously. It seems OK to me, but I would like your sign off on it.


Repository:
  rC Clang

https://reviews.llvm.org/D47101

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaOverload.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/special/class.inhctor/p1.cpp
  test/SemaCXX/attr-noreturn.cpp
  test/SemaCXX/cxx1y-generic-lambdas.cpp
  test/SemaCXX/overload-call.cpp
  test/SemaCXX/overload-member-call.cpp

Index: test/SemaCXX/overload-member-call.cpp
===
--- test/SemaCXX/overload-member-call.cpp
+++ test/SemaCXX/overload-member-call.cpp
@@ -70,7 +70,8 @@
 // Tests the exact text used to note the candidates
 namespace test1 {
   class A {
-template  void foo(T t, unsigned N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
+template 
+void foo(T t, unsigned N); // expected-note {{candidate function template not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
 void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}} 
 void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
 void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
Index: test/SemaCXX/overload-call.cpp
===
--- test/SemaCXX/overload-call.cpp
+++ test/SemaCXX/overload-call.cpp
@@ -338,22 +338,23 @@
 
 // Tests the exact text used to note the candidates
 namespace test1 {
-  template  void foo(T t, unsigned N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
-  void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}} 
-  void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
-  void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
-  void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
-
-  // PR 11857
-  void foo(int n); // expected-note {{candidate function not viable: requires single argument 'n', but 2 arguments were provided}}
-  void foo(unsigned n = 10); // expected-note {{candidate function not viable: allows at most single argument 'n', but 2 arguments were provided}}
-  void bar(int n, int u = 0); // expected-note {{candidate function not viable: requires at least argument 'n', but no arguments were provided}}
-  void baz(int n = 0, int u = 0); // expected-note {{candidate function not viable: requires at most 2 arguments, but 3 were provided}}
-
-  void test() {
-foo(4, "hello"); //expected-error {{no matching function for call to 'foo'}}
-bar(); //expected-error {{no matching function for call to 'bar'}}
-baz(3, 4, 5); // expected-error {{no matching function for call to 'baz'}}
+template 
+void foo(T t, unsigned N);// expected-note {{candidate function template not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
+void foo(int n, char N);  // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}}
+void foo(int n, const char *s, int t);// expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
+void foo(int n, const char *s, int t, ...);   // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
+void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
+
+// PR 11857
+void foo(int n);// expected-note {{candidate function not viable: requires single argument 'n', but 2 arguments were provided}}
+void foo(unsigned n = 10);  // expected-note {{candidate function not viable: allows at most single argument 'n', but 2 arguments were provided}}
+void bar(int n, int u = 0); // expected-note {{candidate function not viable: requires at least argument 'n', but no arguments were provided}}
+void baz(int n = 0

[PATCH] D47090: Implement C++17 .

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

In https://reviews.llvm.org/D47090#1105389, @Quuxplusone wrote:

> > I would prefer if we completed  (according to 
> > the current standard, not the LFTS spec), and then moved it.
> >  Would you be willing to do that instead?
>
> Let me see if I understand. libc++'s `` differs 
> from C++17 `` in at least these ways:
>  (A) It's missing `monotonic_buffer_resource` and 
> `{un,}synchronized_pool_resource`


Those were initially in the LFTS spec, I think they're in LFTS v2.

> (B) It's got different semantics around uses-allocator construction because 
> of https://wg21.link/lwg2969

Issue resolutions should probably be applied to the experimental versions as 
well.

> (C) It's got a different header name

I don't think this is relevant.

> This patch is basically proposing to fix things in the order C-A-B (and fix C 
> by making copies of everything); you're proposing to fix things in the order 
> A-B-C (and fix C by moving everything).
> 
> I have no objection to fixing A in `` if people 
> think that'd be useful. I didn't do that in this patch simply because I'd 
> observed other `` headers already getting replaced with 
> `#error` messages, and it seemed like any further work on the 
> `` headers would have been wasted.
> 
> I don't know who's using `` today, but in 
> theory I worry that fixing B in `` (before 
> doing C) might actually break someone's code.

I'm not concerned with it. We make no promises about ABI and API stability for 
 headers.  Do we implement the LFTS v1, v2, or in future, v3, 
API? I would rather follow the standard spec. I believe
it will actually make transitioning from `` to ``, since 
the behaviour is the same.


Repository:
  rCXX libc++

https://reviews.llvm.org/D47090



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


[PATCH] D47090: Implement C++17 .

2018-05-19 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

I should add that this is the approach I've taken with 
`` with no complaints.


Repository:
  rCXX libc++

https://reviews.llvm.org/D47090



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


[PATCH] D47090: Implement C++17 .

2018-05-19 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a subscriber: dexonsmith.
EricWF added a comment.






Comment at: src/memory_resource.cpp:62
+
+namespace {
+

We certainly don't want a different definition of the global resources in each 
TU. See below.



Comment at: src/memory_resource.cpp:64
+
+union ResourceInitHelper {
+  struct {

This should go inside the library, so we're not emitting an initializer in each 
TU.



Comment at: src/memory_resource.cpp:83
+
+memory_resource * new_delete_resource() _NOEXCEPT {
+return &res_init.resources.new_delete_res;

I think the global resources should be in the unversioned namespace `std::pmr` 
instead of `std::__v::pmr`. Like new/delete and exceptions I suspect we only 
want one definition of these in any given program. I'm considering every 
function from here up to and including `set_default_resource`.

@mclow.lists, @dexonsmith: what do you think?



Comment at: src/memory_resource.cpp:147
+
+template
+struct __mr_holder {

`_Tp`



Comment at: src/memory_resource.cpp:149
+struct __mr_holder {
+memory_resource *res;
+void *ptr;

`__res_`
`__ptr_`
`__size_`
`__align_`



Comment at: src/memory_resource.cpp:180
+struct __pool_resource_chunk {
+size_t bytes;
+size_t alignment;

`__bytes_`
`__alignment_` (or `__align_`)
`__allocation_`
`__next_`


Repository:
  rCXX libc++

https://reviews.llvm.org/D47090



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


[PATCH] D47090: Implement C++17 .

2018-05-19 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added inline comments.



Comment at: src/memory_resource.cpp:62
+
+namespace {
+

Quuxplusone wrote:
> EricWF wrote:
> > We certainly don't want a different definition of the global resources in 
> > each TU. See below.
> @EricWF: I think all of your comments in this file are the result of 
> misreading "src/memory_resource.cpp" as "include/memory_resource".  Or else I 
> *totally* don't understand the current directory organization and you're 
> going to have to instruct me. :)
> 
Woops. I feel dumb now. 


Repository:
  rCXX libc++

https://reviews.llvm.org/D47090



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


[PATCH] D47109: LWG 2969 "polymorphic_allocator::construct() shouldn't pass resource()"

2018-05-19 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

This LGTM. Let's land it and see if anybody complains.


Repository:
  rCXX libc++

https://reviews.llvm.org/D47109



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


[PATCH] D47150: [Clang Tablegen] Add llvm_unreachable() to getModifierName()

2018-05-21 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

LGTM.




Comment at: utils/TableGen/ClangDiagnosticsEmitter.cpp:495
   }
+  llvm_unreachable("invalid modifier type");
 }

Perhaps this should say "unhandled case" or similar?


https://reviews.llvm.org/D47150



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


[PATCH] D47109: LWG 2969 "polymorphic_allocator::construct() shouldn't pass resource()"

2018-05-28 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF closed this revision.
EricWF added a comment.

Committed as r84.


Repository:
  rCXX libc++

https://reviews.llvm.org/D47109



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


[PATCH] D47111: : Implement monotonic_buffer_resource.

2018-05-28 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

FYI I have a full implementation of this laying around as 
https://reviews.llvm.org/D27402 (https://reviews.llvm.org/D27402). But I have 
never taken the time to resolve merge conflicts.
Feel free to steal any of the tests if they're still relevant.




Comment at: include/experimental/memory_resource:429
+size_t __capacity_;
+size_t __alignment_;
+size_t __used_;

I can't imagine we'll need more than 1 byte to represent the alignment.



Comment at: include/experimental/memory_resource:474
+protected:
+void* do_allocate(size_t __bytes, size_t __alignment);
+

Lets add `override` to these functions.



Comment at: src/experimental/memory_resource.cpp:217
+{
+if (void *result = try_allocate_from_chunk(&__original_, bytes, align)) {
+return result;

Drop the braces for conditionals and loops with single statements.


Repository:
  rCXX libc++

https://reviews.llvm.org/D47111



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


[PATCH] D47111: : Implement monotonic_buffer_resource.

2018-05-28 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added inline comments.



Comment at: include/experimental/memory_resource:428
+__monotonic_buffer_header *__next_;
+size_t __capacity_;
+size_t __alignment_;

Can't we determine the capacity in most cases simply using 
`static_cast(this) - static_cast(__start_)`?



Comment at: include/experimental/memory_resource:429
+size_t __capacity_;
+size_t __alignment_;
+size_t __used_;

Quuxplusone wrote:
> EricWF wrote:
> > I can't imagine we'll need more than 1 byte to represent the alignment.
> Even assuming for the sake of argument that that's right, it wouldn't buy us 
> anything here because of padding, would it?
> 
> At the moment, `__alignment_` needs to have enough range to store the `align` 
> parameter passed to `monotonic_buffer_resource::do_allocate`. In an SSE world 
> we should not blithely assume that `align < 256`. We //could// store 
> `lg(align)` in a single byte since `align` is always a power of two and less 
> than 2^64 — but then we're back to the first argument, which is that it'll be 
> padded to 8 bytes anyway so what do we gain.
> Even assuming for the sake of argument that that's right, it wouldn't buy us 
> anything here because of padding, would it?

It could. (A) we don't actually need to include the types trailing padding when 
tail allocating it as a part of a buffer.
and less importantly (B) I'm not sure all ABI's require the trailing padding of 
a type be included when that type is a data member of another type (I might 
just be wrong on this).

I'm also looking into other ways of improving the way your implementation packs 
data, which may cause this to be beneficial. 



Comment at: include/experimental/memory_resource:474
+protected:
+void* do_allocate(size_t __bytes, size_t __alignment);
+

Quuxplusone wrote:
> EricWF wrote:
> > Lets add `override` to these functions.
> I grepped for "override" in `include/` and saw exactly one (accidental?) use 
> in `experimental/filesystem`, so I thought probably libc++ had a policy not 
> to use it for portability reasons. I'll add it throughout, but would like 
> someone to explicitly confirm that
> 
> (A) it's okay to use in this header and wouldn't need to be guarded with a 
> `_LIBCPP_OVERRIDE` macro or anything
> 
> (B) Arthur should //not// bother trying to add it to any //other// headers, 
> not even "for consistency"
The header already assumes a full C++11 implementation (it uses `std::tuple`), 
the `override` keyword will bi available. No need for a special macro.




Comment at: 
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic_buffer.pass.cpp:1
+//===--===//
+//

Instead of testing the whole of `monotonic_buffer` in a single file, this test 
should be broken up into separate files. Roughly one per function, or when it 
makes sense, one per subsection for the lowest level of heading (For example a 
single test for all constructors under `memory.buffer.ctor` ).


Repository:
  rCXX libc++

https://reviews.llvm.org/D47111



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


[PATCH] D47111: : Implement monotonic_buffer_resource.

2018-05-28 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added inline comments.



Comment at: src/experimental/memory_resource.cpp:237
+
+void *result = __res_->allocate(aligned_capacity, align);
+__monotonic_buffer_header *header = (__monotonic_buffer_header *)((char 
*)result + aligned_capacity - header_size);

Quuxplusone wrote:
> For reference, here is where we ask the upstream for a block aligned 
> according to the user's `align`.
> It occurs to me that the upstream might not be able to satisfy such a request 
> (actually, `new_delete_resource` works that way for me because libc++ doesn't 
> support aligned new and delete on OSX), which would make the upstream throw 
> `bad_alloc`. We handle this by passing along the exception. We //could// 
> conceivably handle it by retrying with
> ```
> aligned_capacity += align;
> __res_->allocate(aligned_capacity, alignof(max_align_t));
> header->__alignment_ = alignof(max_align_t);
> ```
> but I'm not sure that that's any of `monotonic_buffer_resource`'s business. 
> Happy to make the patch if you think it ought to be.
I was initially thinking of storing `lg(align)`.


Repository:
  rCXX libc++

https://reviews.llvm.org/D47111



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


[PATCH] D37035: Implement __builtin_LINE() et. al. to support source location capture.

2018-05-29 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 149007.
EricWF added a comment.

- Merge with upstream.

Ping.


https://reviews.llvm.org/D37035

Files:
  docs/LanguageExtensions.rst
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/SourceLocExprScope.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Basic/TokenKinds.def
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ASTImporter.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Parse/ParseExpr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/builtin_FUNCTION.cpp
  test/CodeGenCXX/builtin_LINE.cpp
  test/CodeGenCXX/debug-info-line.cpp
  test/Parser/builtin_source_location.c
  test/Sema/source_location.c
  test/SemaCXX/Inputs/source-location-file.h
  test/SemaCXX/source_location.cpp

Index: test/SemaCXX/source_location.cpp
===
--- /dev/null
+++ test/SemaCXX/source_location.cpp
@@ -0,0 +1,475 @@
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify %s
+// expected-no-diagnostics
+
+#define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
+#define CURRENT_FROM_MACRO() SL::current()
+#define FORWARD(...) __VA_ARGS__
+
+namespace std {
+namespace experimental {
+struct source_location {
+private:
+  unsigned int __m_line = 0;
+  unsigned int __m_col = 0;
+  const char *__m_file = nullptr;
+  const char *__m_func = nullptr;
+public:
+  static constexpr source_location current(
+  const char *__file = __builtin_FILE(),
+  const char *__func = __builtin_FUNCTION(),
+  unsigned int __line = __builtin_LINE(),
+  unsigned int __col = __builtin_COLUMN()) noexcept {
+source_location __loc;
+__loc.__m_line = __line;
+__loc.__m_col = __col;
+__loc.__m_file = __file;
+__loc.__m_func = __func;
+return __loc;
+  }
+  constexpr source_location() = default;
+  constexpr source_location(source_location const &) = default;
+  constexpr unsigned int line() const noexcept { return __m_line; }
+  constexpr unsigned int column() const noexcept { return __m_col; }
+  constexpr const char *file() const noexcept { return __m_file; }
+  constexpr const char *function() const noexcept { return __m_func; }
+};
+} // namespace experimental
+} // namespace std
+
+using SL = std::experimental::source_location;
+
+#include "Inputs/source-location-file.h"
+namespace SLF = source_location_file;
+
+constexpr bool is_equal(const char *LHS, const char *RHS) {
+  while (*LHS != 0 && *RHS != 0) {
+if (*LHS != *RHS)
+  return false;
+++LHS;
+++RHS;
+  }
+  return *LHS == 0 && *RHS == 0;
+}
+
+template 
+constexpr T identity(T t) {
+  return t;
+}
+
+template 
+struct Pair {
+  T first;
+  U second;
+};
+
+template 
+constexpr bool is_same = false;
+template 
+constexpr bool is_same = true;
+
+// test types
+static_assert(is_same);
+static_assert(is_same);
+static_assert(is_same);
+static_assert(is_same);
+
+// test noexcept
+static_assert(noexcept(__builtin_LINE()));
+static_assert(noexcept(__builtin_COLUMN()));
+static_assert(noexcept(__builtin_FILE()));
+static_assert(noexcept(__builtin_FUNCTION()));
+
+//===--===//
+//__builtin_LINE()
+//===--===//
+
+namespace test_line {
+
+static_assert(SL::current().line() == __LINE__);
+static_assert(SL::current().line() == CURRENT_FROM_MACRO().line());
+
+static constexpr SL GlobalS = SL::current();
+
+static_assert(GlobalS.line() == __LINE__ - 2);
+
+// clang-format off
+constexpr bool test_line_fn() {
+  constexpr SL S = SL::current();
+  static_assert(S.line() == (__LINE__ - 1), "");
+  // The start of the call expression to `current()` begins at the token `SL`
+  constexpr int ExpectLine = __LINE__ + 3;
+  constexpr SL S2
+  =
+  SL // Call expression starts here
+  ::
+  current
+  (
+
+  )
+  ;
+  static_assert(S2.line() == ExpectLine, "");
+
+  static_assert(
+  FORWARD(
+ __builtin_LINE
+(
+)
+  )
+== __LINE__ - 1, "");
+  static_assert(\
+\
+  __builtin_LINE()\
+\
+  == __LINE__ - 2, "");
+  static_assert(\
+  _\
+_builtin_LINE()
+  == __LINE__ - 2, "");
+
+  return true;
+}
+// clang-format on
+static_assert(test_line_fn());
+
+static_assert(__builtin_LINE() == __LINE__, "");
+
+co

[PATCH] D47101: [Sema] Use %sub to cleanup overload diagnostics

2018-05-29 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

@rsmith Ping.

Do you have any objection to the addition of "template" to some of the overload 
diagnostics?


Repository:
  rC Clang

https://reviews.llvm.org/D47101



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


[PATCH] D47101: [Sema] Use %sub to cleanup overload diagnostics

2018-05-29 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

Actually I'm OK making this a post-commit review. @rsmith Please let me know if 
you have any thoughts in your own time.


Repository:
  rC Clang

https://reviews.llvm.org/D47101



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


[PATCH] D37035: Implement __builtin_LINE() et. al. to support source location capture.

2018-05-29 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 149009.
EricWF added a comment.

- Fix merge conflicts.


https://reviews.llvm.org/D37035

Files:
  docs/LanguageExtensions.rst
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/SourceLocExprScope.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Basic/TokenKinds.def
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ASTImporter.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Parse/ParseExpr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/builtin_FUNCTION.cpp
  test/CodeGenCXX/builtin_LINE.cpp
  test/CodeGenCXX/debug-info-line.cpp
  test/Parser/builtin_source_location.c
  test/Sema/source_location.c
  test/SemaCXX/Inputs/source-location-file.h
  test/SemaCXX/source_location.cpp

Index: test/SemaCXX/source_location.cpp
===
--- /dev/null
+++ test/SemaCXX/source_location.cpp
@@ -0,0 +1,475 @@
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify %s
+// expected-no-diagnostics
+
+#define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
+#define CURRENT_FROM_MACRO() SL::current()
+#define FORWARD(...) __VA_ARGS__
+
+namespace std {
+namespace experimental {
+struct source_location {
+private:
+  unsigned int __m_line = 0;
+  unsigned int __m_col = 0;
+  const char *__m_file = nullptr;
+  const char *__m_func = nullptr;
+public:
+  static constexpr source_location current(
+  const char *__file = __builtin_FILE(),
+  const char *__func = __builtin_FUNCTION(),
+  unsigned int __line = __builtin_LINE(),
+  unsigned int __col = __builtin_COLUMN()) noexcept {
+source_location __loc;
+__loc.__m_line = __line;
+__loc.__m_col = __col;
+__loc.__m_file = __file;
+__loc.__m_func = __func;
+return __loc;
+  }
+  constexpr source_location() = default;
+  constexpr source_location(source_location const &) = default;
+  constexpr unsigned int line() const noexcept { return __m_line; }
+  constexpr unsigned int column() const noexcept { return __m_col; }
+  constexpr const char *file() const noexcept { return __m_file; }
+  constexpr const char *function() const noexcept { return __m_func; }
+};
+} // namespace experimental
+} // namespace std
+
+using SL = std::experimental::source_location;
+
+#include "Inputs/source-location-file.h"
+namespace SLF = source_location_file;
+
+constexpr bool is_equal(const char *LHS, const char *RHS) {
+  while (*LHS != 0 && *RHS != 0) {
+if (*LHS != *RHS)
+  return false;
+++LHS;
+++RHS;
+  }
+  return *LHS == 0 && *RHS == 0;
+}
+
+template 
+constexpr T identity(T t) {
+  return t;
+}
+
+template 
+struct Pair {
+  T first;
+  U second;
+};
+
+template 
+constexpr bool is_same = false;
+template 
+constexpr bool is_same = true;
+
+// test types
+static_assert(is_same);
+static_assert(is_same);
+static_assert(is_same);
+static_assert(is_same);
+
+// test noexcept
+static_assert(noexcept(__builtin_LINE()));
+static_assert(noexcept(__builtin_COLUMN()));
+static_assert(noexcept(__builtin_FILE()));
+static_assert(noexcept(__builtin_FUNCTION()));
+
+//===--===//
+//__builtin_LINE()
+//===--===//
+
+namespace test_line {
+
+static_assert(SL::current().line() == __LINE__);
+static_assert(SL::current().line() == CURRENT_FROM_MACRO().line());
+
+static constexpr SL GlobalS = SL::current();
+
+static_assert(GlobalS.line() == __LINE__ - 2);
+
+// clang-format off
+constexpr bool test_line_fn() {
+  constexpr SL S = SL::current();
+  static_assert(S.line() == (__LINE__ - 1), "");
+  // The start of the call expression to `current()` begins at the token `SL`
+  constexpr int ExpectLine = __LINE__ + 3;
+  constexpr SL S2
+  =
+  SL // Call expression starts here
+  ::
+  current
+  (
+
+  )
+  ;
+  static_assert(S2.line() == ExpectLine, "");
+
+  static_assert(
+  FORWARD(
+ __builtin_LINE
+(
+)
+  )
+== __LINE__ - 1, "");
+  static_assert(\
+\
+  __builtin_LINE()\
+\
+  == __LINE__ - 2, "");
+  static_assert(\
+  _\
+_builtin_LINE()
+  == __LINE__ - 2, "");
+
+  return true;
+}
+// clang-format on
+static_assert(test_line_fn());
+
+static_assert(__builtin_LINE() == __LINE__, "");
+
+constexpr

[PATCH] D47101: [Sema] Use %sub to cleanup overload diagnostics

2018-05-29 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL333485: [Sema] Use %sub to cleanup overload diagnostics 
(authored by EricWF, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D47101?vs=147649&id=149014#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D47101

Files:
  cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
  cfe/trunk/lib/Sema/SemaOverload.cpp
  cfe/trunk/test/CXX/drs/dr4xx.cpp
  cfe/trunk/test/CXX/special/class.inhctor/p1.cpp
  cfe/trunk/test/SemaCXX/attr-noreturn.cpp
  cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp
  cfe/trunk/test/SemaCXX/overload-call.cpp
  cfe/trunk/test/SemaCXX/overload-member-call.cpp

Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
===
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3525,27 +3525,29 @@
 def note_ovl_too_many_candidates : Note<
 "remaining %0 candidate%s0 omitted; "
 "pass -fshow-overloads=all to show them">;
-def note_ovl_candidate : Note<"candidate "
-"%select{function|function|constructor|"
-"function |function |constructor |"
-"is the implicit default constructor|"
-"is the implicit copy constructor|"
-"is the implicit move constructor|"
-"is the implicit copy assignment operator|"
-"is the implicit move assignment operator|"
-"inherited constructor|"
-"inherited constructor }0%2"
-"%select{| has different class%diff{ (expected $ but has $)|}4,5"
-"| has different number of parameters (expected %4 but has %5)"
-"| has type mismatch at %ordinal4 parameter"
-"%diff{ (expected $ but has $)|}5,6"
-"| has different return type%diff{ ($ expected but has $)|}4,5"
+
+def select_ovl_candidate_kind : TextSubstitution<
+  "%select{function|function|constructor|"
+"constructor (the implicit default constructor)|"
+"constructor (the implicit copy constructor)|"
+"constructor (the implicit move constructor)|"
+"function (the implicit copy assignment operator)|"
+"function (the implicit move assignment operator)|"
+"inherited constructor}0%select{| template| %2}1">;
+
+def note_ovl_candidate : Note<
+"candidate %sub{select_ovl_candidate_kind}0,1,3"
+"%select{| has different class%diff{ (expected $ but has $)|}5,6"
+"| has different number of parameters (expected %5 but has %6)"
+"| has type mismatch at %ordinal5 parameter"
+"%diff{ (expected $ but has $)|}6,7"
+"| has different return type%diff{ ($ expected but has $)|}5,6"
 "| has different qualifiers (expected "
 "%select{none|const|restrict|const and restrict|volatile|const and volatile"
-"|volatile and restrict|const, volatile, and restrict}4 but found "
+"|volatile and restrict|const, volatile, and restrict}5 but found "
 "%select{none|const|restrict|const and restrict|volatile|const and volatile"
-"|volatile and restrict|const, volatile, and restrict}5)"
-"| has different exception specification}3">;
+"|volatile and restrict|const, volatile, and restrict}6)"
+"| has different exception specification}4">;
 
 def note_ovl_candidate_inherited_constructor : Note<
 "constructor from base class %0 inherited here">;
@@ -3615,225 +3617,97 @@
 
 // Note that we don't treat templates differently for this diagnostic.
 def note_ovl_candidate_arity : Note<"candidate "
-"%select{function|function|constructor|function|function|constructor|"
-"constructor (the implicit default constructor)|"
-"constructor (the implicit copy constructor)|"
-"constructor (the implicit move constructor)|"
-"function (the implicit copy assignment operator)|"
-"function (the implicit move assignment operator)|"
-"inherited constructor|"
-"inherited constructor}0 %select{|template }1"
-"not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 "
-"%plural{1:was|:were}4 provided">;
+"%sub{select_ovl_candidate_kind}0,1,2 not viable: "
+"requires%select{ at least| at most|}3 %4 argument%s4, but %5 "
+"%plural{1:was|:were}5 provided">;
 
 def note_ovl_candidate_arity_one : Note<"candidate "
-"%select{function|function|constructor|function|function|constructor|"
-"constructor (the implicit default constructor)|"
-"constructor (the implicit copy constructor)|"
-"constructor (the implicit move constructor)|"
-"function (the implicit copy assignment operator)|"
-"function (the implicit move assignment operator)|"
-"inherited constructor|"
-"inherited constructor}0 %select{|template }1not viable: "
-"%select{requires at least|allows at most single|requires single}2 "
-"argument %3, but %plural{0:no|:%4}4 arguments were provided">;
+"%sub{select_ovl_candidate_kind}0,1,2 not viable: "
+"%select{requires at least|allows at most single|requires

[PATCH] D38757: [libc++] Fix PR34898 - vector iterator constructors and assign method perform push_back instead of emplace_back.

2017-10-17 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.

In https://reviews.llvm.org/D38757#897536, @dlj wrote:

> Hmm, looking more at this change... while it does make the behaviour 
> consistent for Forward and Input iterators, I think it's just making them 
> both do the wrong thing.
>
> Specifically, based on this:
>
> "... i and j denote iterators satisfying input iterator requirements and 
> refer to elements implicitly convertible to value_­type..."
>
> https://timsong-cpp.github.io/cppwp/n4659/container.requirements#sequence.reqmts-3
>
> So, for example, in test_emplacable_concept, the vector constructor should be 
> diagnosed, because there is no way to *implicitly* convert from the 
> dereferenced iterator type to the inserted type. The selected constructor is 
> explicit. Using emplacement just omits a *second* potentially-expensive 
> conversion: the explicit constructor behaviour (invoked through forwarding) 
> may still be undesired.


No, these types should be EmplaceConstructed if construction is supposed to 
occur when we are constructing a new element in the container, which is what 
this test does. These elements *need* to be constructed using the Allocator. 
The implicit construction is useful in PR34906 
, which we implicitly construct a 
value and then assign it to an already existing container.

This patch is correct to forward to emplace instead of push_back.




Comment at: 
test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp:55
 int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 1, 0};
-int* an = a + sizeof(a)/sizeof(a[0]);
+int* an = a + sizeof(a) / sizeof(a[0]);
 std::allocator alloc;

Sorry, this is all just re-formatting.



Comment at: test/support/emplace_constructible.h:6
+
+#if TEST_STD_VER >= 11
+  template 

THis file needs re-formatting.


https://reviews.llvm.org/D38757



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


[PATCH] D38757: [libc++] Fix PR34898 - vector iterator constructors and assign method perform push_back instead of emplace_back.

2017-10-17 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 119301.
EricWF added a comment.

- Update whitespace.


https://reviews.llvm.org/D38757

Files:
  include/deque
  include/list
  include/vector
  test/std/containers/sequences/deque/deque.cons/assign_iter_iter.pass.cpp
  test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp
  test/std/containers/sequences/deque/deque.cons/iter_iter_alloc.pass.cpp
  test/std/containers/sequences/list/list.cons/input_iterator.pass.cpp
  test/std/containers/sequences/vector/vector.cons/assign_iter_iter.pass.cpp
  test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
  
test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
  test/support/container_test_types.h
  test/support/emplace_constructible.h

Index: test/support/emplace_constructible.h
===
--- /dev/null
+++ test/support/emplace_constructible.h
@@ -0,0 +1,74 @@
+#ifndef TEST_SUPPORT_EMPLACE_CONSTRUCTIBLE_H
+#define TEST_SUPPORT_EMPLACE_CONSTRUCTIBLE_H
+
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 11
+template 
+struct EmplaceConstructible {
+  T value;
+  explicit EmplaceConstructible(T value) : value(value) {}
+  EmplaceConstructible(EmplaceConstructible const&) = delete;
+};
+
+template 
+struct EmplaceConstructibleAndMoveInsertable {
+  int copied = 0;
+  T value;
+  explicit EmplaceConstructibleAndMoveInsertable(T value) : value(value) {}
+
+  EmplaceConstructibleAndMoveInsertable(
+  EmplaceConstructibleAndMoveInsertable&& Other)
+  : copied(Other.copied + 1), value(std::move(Other.value)) {}
+};
+
+template 
+struct EmplaceConstructibleAndMoveable {
+  int copied = 0;
+  int assigned = 0;
+  T value;
+  explicit EmplaceConstructibleAndMoveable(T value) noexcept : value(value) {}
+
+  EmplaceConstructibleAndMoveable(EmplaceConstructibleAndMoveable&& Other)
+  noexcept : copied(Other.copied + 1),
+ value(std::move(Other.value)) {}
+
+  EmplaceConstructibleAndMoveable&
+  operator=(EmplaceConstructibleAndMoveable&& Other) noexcept {
+copied = Other.copied;
+assigned = Other.assigned + 1;
+value = std::move(Other.value);
+return *this;
+  }
+};
+
+template 
+struct EmplaceConstructibleMoveableAndAssignable {
+  int copied = 0;
+  int assigned = 0;
+  T value;
+  explicit EmplaceConstructibleMoveableAndAssignable(T value) noexcept
+  : value(value) {}
+
+  EmplaceConstructibleMoveableAndAssignable(
+  EmplaceConstructibleMoveableAndAssignable&& Other) noexcept
+  : copied(Other.copied + 1),
+value(std::move(Other.value)) {}
+
+  EmplaceConstructibleMoveableAndAssignable&
+  operator=(EmplaceConstructibleMoveableAndAssignable&& Other) noexcept {
+copied = Other.copied;
+assigned = Other.assigned + 1;
+value = std::move(Other.value);
+return *this;
+  }
+
+  EmplaceConstructibleMoveableAndAssignable& operator=(T xvalue) {
+value = std::move(xvalue);
+++assigned;
+return *this;
+  }
+};
+#endif
+
+#endif // TEST_SUPPORT_EMPLACE_CONSTRUCTIBLE_H
Index: test/support/container_test_types.h
===
--- test/support/container_test_types.h
+++ test/support/container_test_types.h
@@ -234,6 +234,19 @@
   return &c;
 }
 
+template 
+struct ExpectConstructGuard {
+  ExpectConstructGuard(int N)  {
+auto CC = getConstructController();
+assert(!CC->unchecked());
+CC->expect(N);
+  }
+
+  ~ExpectConstructGuard() {
+assert(!getConstructController()->unchecked());
+  }
+};
+
 //===--===//
 //   ContainerTestAllocator
 //===--===//
@@ -417,7 +430,12 @@
   return arg.data;
 }
   };
-
+  template 
+  class vector;
+  template 
+  class deque;
+  template 
+  class list;
   template 
   class map;
   template 
@@ -444,6 +462,13 @@
 // TCT - Test container type
 namespace TCT {
 
+template >
+using vector = std::vector >;
+template >
+using deque = std::deque >;
+template >
+using list = std::list >;
+
 template , class Value = CopyInsertable<2>,
   class ValueTp = std::pair >
 using unordered_map =
@@ -488,5 +513,4 @@
 
 } // end namespace TCT
 
-
 #endif // SUPPORT_CONTAINER_TEST_TYPES_H
Index: test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
===
--- test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
+++ test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
@@ -21,56 +21,152 @@
 #include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
+#if TEST_STD_VER >= 11
+#include "emplace_constructible.h"
+#include "container_test_types.h"
+#endif
 
 template 
-void
-test(Iterator first, Iterator last, const A& a)
-{

[PATCH] D38757: [libc++] Fix PR34898 - vector iterator constructors and assign method perform push_back instead of emplace_back.

2017-10-17 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL315994: [libc++] Fix PR34898 - vector iterator constructors 
and assign method perform… (authored by EricWF).

Changed prior to commit:
  https://reviews.llvm.org/D38757?vs=119301&id=119302#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D38757

Files:
  libcxx/trunk/include/deque
  libcxx/trunk/include/list
  libcxx/trunk/include/vector
  
libcxx/trunk/test/std/containers/sequences/deque/deque.cons/assign_iter_iter.pass.cpp
  libcxx/trunk/test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp
  
libcxx/trunk/test/std/containers/sequences/deque/deque.cons/iter_iter_alloc.pass.cpp
  
libcxx/trunk/test/std/containers/sequences/list/list.cons/input_iterator.pass.cpp
  
libcxx/trunk/test/std/containers/sequences/vector/vector.cons/assign_iter_iter.pass.cpp
  
libcxx/trunk/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
  
libcxx/trunk/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
  libcxx/trunk/test/support/container_test_types.h
  libcxx/trunk/test/support/emplace_constructible.h

Index: libcxx/trunk/include/deque
===
--- libcxx/trunk/include/deque
+++ libcxx/trunk/include/deque
@@ -1356,7 +1356,6 @@
 iterator insert(const_iterator __p, initializer_list __il)
 {return insert(__p, __il.begin(), __il.end());}
 #endif  // _LIBCPP_CXX03_LANG
-
 iterator insert(const_iterator __p, const value_type& __v);
 iterator insert(const_iterator __p, size_type __n, const value_type& __v);
 template 
@@ -2224,7 +2223,11 @@
!__is_forward_iterator<_InpIter>::value>::type*)
 {
 for (; __f != __l; ++__f)
+#ifdef _LIBCPP_CXX03_LANG
 push_back(*__f);
+#else
+emplace_back(*__f);
+#endif
 }
 
 template 
Index: libcxx/trunk/include/vector
===
--- libcxx/trunk/include/vector
+++ libcxx/trunk/include/vector
@@ -674,6 +674,17 @@
 const value_type* data() const _NOEXCEPT
 {return _VSTD::__to_raw_pointer(this->__begin_);}
 
+#ifdef _LIBCPP_CXX03_LANG
+_LIBCPP_INLINE_VISIBILITY
+void __emplace_back(const value_type& __x) { push_back(__x); }
+#else
+template 
+_LIBCPP_INLINE_VISIBILITY
+void __emplace_back(_Arg&& __arg) {
+  emplace_back(_VSTD::forward<_Arg>(__arg));
+}
+#endif
+
 _LIBCPP_INLINE_VISIBILITY void push_back(const_reference __x);
 
 #ifndef _LIBCPP_CXX03_LANG
@@ -1128,7 +1139,7 @@
 __get_db()->__insert_c(this);
 #endif
 for (; __first != __last; ++__first)
-push_back(*__first);
+__emplace_back(*__first);
 }
 
 template 
@@ -1145,7 +1156,7 @@
 __get_db()->__insert_c(this);
 #endif
 for (; __first != __last; ++__first)
-push_back(*__first);
+__emplace_back(*__first);
 }
 
 template 
@@ -1365,7 +1376,7 @@
 {
 clear();
 for (; __first != __last; ++__first)
-push_back(*__first);
+__emplace_back(*__first);
 }
 
 template 
Index: libcxx/trunk/include/list
===
--- libcxx/trunk/include/list
+++ libcxx/trunk/include/list
@@ -992,6 +992,15 @@
 void push_front(const value_type& __x);
 void push_back(const value_type& __x);
 
+#ifndef _LIBCPP_CXX03_LANG
+template 
+_LIBCPP_INLINE_VISIBILITY
+void __emplace_back(_Arg&& __arg) { emplace_back(_VSTD::forward<_Arg>(__arg)); }
+#else
+_LIBCPP_INLINE_VISIBILITY
+void __emplace_back(value_type const& __arg) { push_back(__arg); }
+#endif
+
 iterator insert(const_iterator __p, const value_type& __x);
 iterator insert(const_iterator __p, size_type __n, const value_type& __x);
 template 
@@ -1189,7 +1198,7 @@
 __get_db()->__insert_c(this);
 #endif
 for (; __f != __l; ++__f)
-push_back(*__f);
+__emplace_back(*__f);
 }
 
 template 
@@ -1202,7 +1211,7 @@
 __get_db()->__insert_c(this);
 #endif
 for (; __f != __l; ++__f)
-push_back(*__f);
+__emplace_back(*__f);
 }
 
 template 
Index: libcxx/trunk/test/support/emplace_constructible.h
===
--- libcxx/trunk/test/support/emplace_constructible.h
+++ libcxx/trunk/test/support/emplace_constructible.h
@@ -0,0 +1,74 @@
+#ifndef TEST_SUPPORT_EMPLACE_CONSTRUCTIBLE_H
+#define TEST_SUPPORT_EMPLACE_CONSTRUCTIBLE_H
+
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 11
+template 
+struct EmplaceConstructible {
+  T value;
+  explicit EmplaceConstructible(T value) : value(value) {}
+  EmplaceConstructible(EmplaceConstructible const&) = delete;
+};
+
+template 
+struct EmplaceConstructibleAndMoveInsertable {
+  int copied = 0;
+  T value;
+  explicit EmplaceConstructibleAndMoveInsertable(T value) : value(value) {}
+
+  EmplaceConstructibleAndMoveInsertable(

[PATCH] D45179: [libc++] Add _LIBCPP_ENABLE_NODISCARD and _LIBCPP_NODISCARD_EXT to allow pre-C++2a [[nodiscard]]

2018-09-06 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

I don't think it ever landed. I'll try to get it in this week.


https://reviews.llvm.org/D45179



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


[PATCH] D49509: [libc++] Allow running ABI list tests with different ABI versions

2018-07-19 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

LGTM. Though it might be worth noting that we don't really have an "ABI v2" 
yet; we're just staging it ATM.


Repository:
  rL LLVM

https://reviews.llvm.org/D49509



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


[PATCH] D49067: Stop wrapping __has_include in another macro

2018-07-23 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a reviewer: mclow.lists.
EricWF added a subscriber: mclow.lists.
EricWF added a comment.

Where are the special lexing rules specified?




Comment at: include/__config:153
+#ifndef __has_include
+#define __has_include(...) 0
 #endif

I do prefer not hijacking this name, but if it's needed to make things work, 
then it's OK with me.

@mclow.lists Are you OK if we steal this identifier and `#define` it ourselves.


Repository:
  rCXX libc++

https://reviews.llvm.org/D49067



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


[PATCH] D49774: [libc++] Use __int128_t to represent file_time_type.

2018-07-24 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF created this revision.
EricWF added reviewers: mclow.lists, ldionne, joerg, arthur.j.odwyer.
Herald added subscribers: cfe-commits, christof.

The ``file_time_type`` time point is used to represent the write times for 
files.
Its job is to act as part of a C++ wrapper for less ideal system interfaces. The
underlying filesystem uses the ``timespec`` struct for the same purpose.

However, the initial implementation of ``file_time_type`` could not represent
either the range or resolution of ``timespec``, making it unsuitable. Fixing
this requires an implementation which uses more than 64 bits to store the
time point.

I primarily considered two solutions: Using ``__int128_t`` and using a
arithmetic emulation of ``timespec``. Each has its pros and cons, and both
come with more than one complication.

However, after a lot of consideration, I decided on using `__int128_t`. This 
patch implements that change.

Please see the FileTimeType Design Document 
 for more information.


Repository:
  rCXX libc++

https://reviews.llvm.org/D49774

Files:
  include/experimental/filesystem
  src/chrono.cpp
  src/experimental/filesystem/filesystem_common.h
  src/experimental/filesystem/operations.cpp
  src/include/apple_availability.h
  
test/libcxx/experimental/filesystem/class.directory_entry/directory_entry.mods/last_write_time.sh.cpp
  test/libcxx/experimental/filesystem/convert_file_time.sh.cpp
  
test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp
  
test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp

Index: test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
===
--- test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
+++ test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
@@ -30,13 +30,87 @@
 #include 
 #include 
 
+#include 
+#include 
+
 using namespace fs;
 
-struct Times { std::time_t access, write; };
+using TimeSpec = struct ::timespec;
+using StatT = struct ::stat;
+
+using Sec = std::chrono::duration;
+using Hours = std::chrono::hours;
+using Minutes = std::chrono::minutes;
+using MicroSec = std::chrono::duration;
+using NanoSec = std::chrono::duration;
+using std::chrono::duration_cast;
+
+#if defined(__APPLE__)
+TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
+TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
+#else
+TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
+TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
+#endif
+
+bool ConvertToTimeSpec(TimeSpec& ts, file_time_type ft) {
+  using SecFieldT = decltype(TimeSpec::tv_sec);
+  using NSecFieldT = decltype(TimeSpec::tv_nsec);
+  using SecLim = std::numeric_limits;
+  using NSecLim = std::numeric_limits;
+
+  auto secs = duration_cast(ft.time_since_epoch());
+  auto nsecs = duration_cast(ft.time_since_epoch() - secs);
+  if (nsecs.count() < 0) {
+if (Sec::min().count() > SecLim::min()) {
+  secs += Sec(1);
+  nsecs -= Sec(1);
+} else {
+  nsecs = NanoSec(0);
+  //return false;
+}
+  }
+  if (SecLim::max() < secs.count() || SecLim::min() > secs.count())
+return false;
+  if (NSecLim::max() < nsecs.count() || NSecLim::min() > nsecs.count())
+return false;
+  ts.tv_sec = secs.count();
+  ts.tv_nsec = nsecs.count();
+  return true;
+}
+
+bool ConvertFromTimeSpec(file_time_type& ft, TimeSpec ts) {
+  auto secs_part = duration_cast(Sec(ts.tv_sec));
+  if (duration_cast(secs_part).count() != ts.tv_sec)
+return false;
+  auto subsecs = duration_cast(NanoSec(ts.tv_nsec));
+  auto dur = secs_part + subsecs;
+  if (dur < secs_part && subsecs.count() >= 0)
+return false;
+  ft = file_time_type(dur);
+  return true;
+}
+
+bool CompareTimeExact(TimeSpec ts, TimeSpec ts2) {
+  return ts2.tv_sec == ts.tv_sec && ts2.tv_nsec == ts.tv_nsec;
+}
+bool CompareTimeExact(file_time_type ft, TimeSpec ts) {
+  TimeSpec ts2 = {};
+  if (!ConvertToTimeSpec(ts2, ft))
+return false;
+  return CompareTimeExact(ts, ts2);
+}
+bool CompareTimeExact(TimeSpec ts, file_time_type ft) {
+  return CompareTimeExact(ft, ts);
+}
+
+struct Times {
+  TimeSpec access, write;
+};
 
 Times GetTimes(path const& p) {
 using Clock = file_time_type::clock;
-struct ::stat st;
+StatT st;
 if (::stat(p.c_str(), &st) == -1) {
 std::error_code ec(errno, std::generic_category());
 #ifndef TEST_HAS_NO_EXCEPTIONS
@@ -46,47 +120,29 @@
 std::exit(EXIT_FAILURE);
 #endif
 }
-return {st.st_atime, st.st_mtime};
+return {extract_atime(st), extract_mtime(st)};
 }
 
-std::time_t LastAccessTime(path const& p) {
-return GetTimes(p).access;
-}
+TimeSpec LastAccessTime(path const& p) { return GetTimes(p).access; }
 
-std::time_t LastWriteTime(path const& p)

[PATCH] D49773: Add new file test/support/test_comparisons.h

2018-07-24 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

Some of this stuff is marked `constexpr` despite it requiring C++14 constexpr 
semantics.  Can they be non-constexpr in C++11 and still function? Or should 
the header explicitly require C++14 to be included?


https://reviews.llvm.org/D49773



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


[PATCH] D49774: [libc++] Use __int128_t to represent file_time_type.

2018-07-24 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

This is the final change I need to land before adding 
``, so I don't plan to let this review linger long.

If you have any strong objections, please speak now or forever hold your peace 
(or at least until the next ABI break, whichever comes first).


Repository:
  rCXX libc++

https://reviews.llvm.org/D49774



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


[PATCH] D49773: Add new file test/support/test_comparisons.h

2018-07-24 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

Otherwise, I'm quite happy with this patch.

The only downside I see is if `testComparisons6` fails, it will report the 
source of the failure as being in the header, and not provide information about 
the callee.
But I think having simpler tests to read and write is more important. Hopefully 
they shouldn't be falling too often anyway :-P


https://reviews.llvm.org/D49773



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


[PATCH] D49774: [libc++] Use __int128_t to represent file_time_type.

2018-07-24 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

In https://reviews.llvm.org/D49774#1174565, @mclow.lists wrote:

> I haven't reviewed this closely, but you might want to look at 
> http://wg21.link/P0355, where we added a `file_clock` and `file_time` types.


Thanks for the information. It doesn't look to have too much bearing on this 
from a design standpoint. Except to note that it seems to solve
the streaming problem by adding explicit streaming overload for time points.


Repository:
  rCXX libc++

https://reviews.llvm.org/D49774



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


[PATCH] D49782: [libcxx] [windows] Fix warning about comparing ints of different signs

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

LGTM.


Repository:
  rCXX libc++

https://reviews.llvm.org/D49782



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


[PATCH] D49774: [libc++] Use __int128_t to represent file_time_type.

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

In https://reviews.llvm.org/D49774#1175679, @BillyONeal wrote:

> In https://reviews.llvm.org/D49774#1175650, @ldionne wrote:
>
> > In https://reviews.llvm.org/D49774#1175543, @BillyONeal wrote:
> >
> > > In https://reviews.llvm.org/D49774#1175131, @mclow.lists wrote:
> > >
> > > > Another problem (that Eric and I discussed last night) is that 
> > > > filesystem is part of C++17, and `file_clock` is C++20. So we need a 
> > > > solution for C++17 as well.
> > >
> > >
> > > It seems like we need to fix C++20 to allow that to be a typedef to a 
> > > type in std::filesystem or that will be ABI breaking for MSVC++. IMO we 
> > > should fix the spec to allow that rather than make libc++ jump through 
> > > insane hoops.
> >
> >
> > We could also just provide `file_clock` "early" in C++17. Strictly speaking 
> > that may make our implementation non-conforming, but IDK how big of a deal 
> > this would be?
>
>
> Sure, libc++ could do that. But because msvc++ and libstdc++ have already 
> shipped this thing I think the spec will have to change.
>
> No real user cares about the associated namespaces of a clock anyway.


Agreed. I don't think this spec will land as-is.




Comment at: 
test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp:589
+  std::cerr << new_ts.tv_sec << "\n";
+  std::cerr << new_ts.tv_nsec << "\n";
+  TEST_CHECK(ts[1].tv_sec == new_ts.tv_sec);

TODO: remove this.


Repository:
  rCXX libc++

https://reviews.llvm.org/D49774



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


[PATCH] D49813: [libc++] Make compile with gcc 4.8.5

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

Urg. That's an old compiler. But this looks OK to me.


Repository:
  rCXX libc++

https://reviews.llvm.org/D49813



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


[PATCH] D49774: [libc++] Use __int128_t to represent file_time_type.

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 157349.
EricWF added a comment.

Update with misc cleanups.


https://reviews.llvm.org/D49774

Files:
  include/experimental/filesystem
  src/chrono.cpp
  src/experimental/filesystem/filesystem_common.h
  src/experimental/filesystem/operations.cpp
  src/include/apple_availability.h
  
test/libcxx/experimental/filesystem/class.directory_entry/directory_entry.mods/last_write_time.sh.cpp
  test/libcxx/experimental/filesystem/convert_file_time.sh.cpp
  
test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp
  
test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp

Index: test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
===
--- test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
+++ test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
@@ -30,13 +30,86 @@
 #include 
 #include 
 
+#include 
+#include 
+
 using namespace fs;
 
-struct Times { std::time_t access, write; };
+using TimeSpec = struct ::timespec;
+using StatT = struct ::stat;
+
+using Sec = std::chrono::duration;
+using Hours = std::chrono::hours;
+using Minutes = std::chrono::minutes;
+using MicroSec = std::chrono::duration;
+using NanoSec = std::chrono::duration;
+using std::chrono::duration_cast;
+
+#if defined(__APPLE__)
+TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
+TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
+#else
+TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
+TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
+#endif
+
+bool ConvertToTimeSpec(TimeSpec& ts, file_time_type ft) {
+  using SecFieldT = decltype(TimeSpec::tv_sec);
+  using NSecFieldT = decltype(TimeSpec::tv_nsec);
+  using SecLim = std::numeric_limits;
+  using NSecLim = std::numeric_limits;
+
+  auto secs = duration_cast(ft.time_since_epoch());
+  auto nsecs = duration_cast(ft.time_since_epoch() - secs);
+  if (nsecs.count() < 0) {
+if (Sec::min().count() > SecLim::min()) {
+  secs += Sec(1);
+  nsecs -= Sec(1);
+} else {
+  nsecs = NanoSec(0);
+}
+  }
+  if (SecLim::max() < secs.count() || SecLim::min() > secs.count())
+return false;
+  if (NSecLim::max() < nsecs.count() || NSecLim::min() > nsecs.count())
+return false;
+  ts.tv_sec = secs.count();
+  ts.tv_nsec = nsecs.count();
+  return true;
+}
+
+bool ConvertFromTimeSpec(file_time_type& ft, TimeSpec ts) {
+  auto secs_part = duration_cast(Sec(ts.tv_sec));
+  if (duration_cast(secs_part).count() != ts.tv_sec)
+return false;
+  auto subsecs = duration_cast(NanoSec(ts.tv_nsec));
+  auto dur = secs_part + subsecs;
+  if (dur < secs_part && subsecs.count() >= 0)
+return false;
+  ft = file_time_type(dur);
+  return true;
+}
+
+bool CompareTimeExact(TimeSpec ts, TimeSpec ts2) {
+  return ts2.tv_sec == ts.tv_sec && ts2.tv_nsec == ts.tv_nsec;
+}
+bool CompareTimeExact(file_time_type ft, TimeSpec ts) {
+  TimeSpec ts2 = {};
+  if (!ConvertToTimeSpec(ts2, ft))
+return false;
+  return CompareTimeExact(ts, ts2);
+}
+bool CompareTimeExact(TimeSpec ts, file_time_type ft) {
+  return CompareTimeExact(ft, ts);
+}
+
+struct Times {
+  TimeSpec access, write;
+};
 
 Times GetTimes(path const& p) {
 using Clock = file_time_type::clock;
-struct ::stat st;
+StatT st;
 if (::stat(p.c_str(), &st) == -1) {
 std::error_code ec(errno, std::generic_category());
 #ifndef TEST_HAS_NO_EXCEPTIONS
@@ -46,47 +119,29 @@
 std::exit(EXIT_FAILURE);
 #endif
 }
-return {st.st_atime, st.st_mtime};
+return {extract_atime(st), extract_mtime(st)};
 }
 
-std::time_t LastAccessTime(path const& p) {
-return GetTimes(p).access;
-}
+TimeSpec LastAccessTime(path const& p) { return GetTimes(p).access; }
 
-std::time_t LastWriteTime(path const& p) {
-return GetTimes(p).write;
-}
+TimeSpec LastWriteTime(path const& p) { return GetTimes(p).write; }
 
-std::pair GetSymlinkTimes(path const& p) {
-using Clock = file_time_type::clock;
-struct ::stat st;
-if (::lstat(p.c_str(), &st) == -1) {
-std::error_code ec(errno, std::generic_category());
+std::pair GetSymlinkTimes(path const& p) {
+  using Clock = file_time_type::clock;
+  StatT st;
+  if (::lstat(p.c_str(), &st) == -1) {
+std::error_code ec(errno, std::generic_category());
 #ifndef TEST_HAS_NO_EXCEPTIONS
 throw ec;
 #else
 std::cerr << ec.message() << std::endl;
 std::exit(EXIT_FAILURE);
 #endif
 }
-return {st.st_atime, st.st_mtime};
+return {extract_atime(st), extract_mtime(st)};
 }
 
 namespace {
-bool TestSupportsNegativeTimes() {
-using namespace std::chrono;
-std::error_code ec;
-std::time_t old_write_time, new_write_time;
-{ // WARNING: Do not assert in this scope.
-scoped_test_env env;
-

[PATCH] D49774: [libc++] Use __int128_t to represent file_time_type.

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

I'm going to go ahead and commit this now. We can address concerns about the 
future C++20 spec in follow up commits.


https://reviews.llvm.org/D49774



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


[PATCH] D49774: [libc++] Use __int128_t to represent file_time_type.

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCXX337960: [libc++] Use __int128_t to represent 
file_time_type. (authored by EricWF, committed by ).

Repository:
  rCXX libc++

https://reviews.llvm.org/D49774

Files:
  include/experimental/filesystem
  src/chrono.cpp
  src/experimental/filesystem/filesystem_common.h
  src/experimental/filesystem/operations.cpp
  src/include/apple_availability.h
  
test/libcxx/experimental/filesystem/class.directory_entry/directory_entry.mods/last_write_time.sh.cpp
  test/libcxx/experimental/filesystem/convert_file_time.sh.cpp
  
test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp
  
test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp

Index: test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
===
--- test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
+++ test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
@@ -30,13 +30,86 @@
 #include 
 #include 
 
+#include 
+#include 
+
 using namespace fs;
 
-struct Times { std::time_t access, write; };
+using TimeSpec = struct ::timespec;
+using StatT = struct ::stat;
+
+using Sec = std::chrono::duration;
+using Hours = std::chrono::hours;
+using Minutes = std::chrono::minutes;
+using MicroSec = std::chrono::duration;
+using NanoSec = std::chrono::duration;
+using std::chrono::duration_cast;
+
+#if defined(__APPLE__)
+TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
+TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
+#else
+TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
+TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
+#endif
+
+bool ConvertToTimeSpec(TimeSpec& ts, file_time_type ft) {
+  using SecFieldT = decltype(TimeSpec::tv_sec);
+  using NSecFieldT = decltype(TimeSpec::tv_nsec);
+  using SecLim = std::numeric_limits;
+  using NSecLim = std::numeric_limits;
+
+  auto secs = duration_cast(ft.time_since_epoch());
+  auto nsecs = duration_cast(ft.time_since_epoch() - secs);
+  if (nsecs.count() < 0) {
+if (Sec::min().count() > SecLim::min()) {
+  secs += Sec(1);
+  nsecs -= Sec(1);
+} else {
+  nsecs = NanoSec(0);
+}
+  }
+  if (SecLim::max() < secs.count() || SecLim::min() > secs.count())
+return false;
+  if (NSecLim::max() < nsecs.count() || NSecLim::min() > nsecs.count())
+return false;
+  ts.tv_sec = secs.count();
+  ts.tv_nsec = nsecs.count();
+  return true;
+}
+
+bool ConvertFromTimeSpec(file_time_type& ft, TimeSpec ts) {
+  auto secs_part = duration_cast(Sec(ts.tv_sec));
+  if (duration_cast(secs_part).count() != ts.tv_sec)
+return false;
+  auto subsecs = duration_cast(NanoSec(ts.tv_nsec));
+  auto dur = secs_part + subsecs;
+  if (dur < secs_part && subsecs.count() >= 0)
+return false;
+  ft = file_time_type(dur);
+  return true;
+}
+
+bool CompareTimeExact(TimeSpec ts, TimeSpec ts2) {
+  return ts2.tv_sec == ts.tv_sec && ts2.tv_nsec == ts.tv_nsec;
+}
+bool CompareTimeExact(file_time_type ft, TimeSpec ts) {
+  TimeSpec ts2 = {};
+  if (!ConvertToTimeSpec(ts2, ft))
+return false;
+  return CompareTimeExact(ts, ts2);
+}
+bool CompareTimeExact(TimeSpec ts, file_time_type ft) {
+  return CompareTimeExact(ft, ts);
+}
+
+struct Times {
+  TimeSpec access, write;
+};
 
 Times GetTimes(path const& p) {
 using Clock = file_time_type::clock;
-struct ::stat st;
+StatT st;
 if (::stat(p.c_str(), &st) == -1) {
 std::error_code ec(errno, std::generic_category());
 #ifndef TEST_HAS_NO_EXCEPTIONS
@@ -46,47 +119,29 @@
 std::exit(EXIT_FAILURE);
 #endif
 }
-return {st.st_atime, st.st_mtime};
+return {extract_atime(st), extract_mtime(st)};
 }
 
-std::time_t LastAccessTime(path const& p) {
-return GetTimes(p).access;
-}
+TimeSpec LastAccessTime(path const& p) { return GetTimes(p).access; }
 
-std::time_t LastWriteTime(path const& p) {
-return GetTimes(p).write;
-}
+TimeSpec LastWriteTime(path const& p) { return GetTimes(p).write; }
 
-std::pair GetSymlinkTimes(path const& p) {
-using Clock = file_time_type::clock;
-struct ::stat st;
-if (::lstat(p.c_str(), &st) == -1) {
-std::error_code ec(errno, std::generic_category());
+std::pair GetSymlinkTimes(path const& p) {
+  using Clock = file_time_type::clock;
+  StatT st;
+  if (::lstat(p.c_str(), &st) == -1) {
+std::error_code ec(errno, std::generic_category());
 #ifndef TEST_HAS_NO_EXCEPTIONS
 throw ec;
 #else
 std::cerr << ec.message() << std::endl;
 std::exit(EXIT_FAILURE);
 #endif
 }
-return {st.st_atime, st.st_mtime};
+return {extract_atime(st), extract_mtime(st)};
 }
 
 namespace {
-bool TestSupportsNegativeTimes() {
-using namespace std::chrono;
-std::error_code ec;
-

[PATCH] D49813: [libc++] Make compile with gcc 4.8.5

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF closed this revision.
EricWF added a comment.

r337962.

Thanks.


Repository:
  rCXX libc++

https://reviews.llvm.org/D49813



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


[PATCH] D49828: [libc++] Add hack to allow ubsan to work w/o compiler-rt (__muloti4 is undefined)

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF created this revision.
EricWF added reviewers: mclow.lists, ldionne, rsmith, jyknight, echristo.
Herald added a subscriber: dberris.

Using __int128_t with UBSAN causes link errors unless compiler-rt is providing 
the runtime library.
Specifically ubsan generates calls to __muloti4 but libgcc doesn't provide a 
definition.

In order to avoid this, and allow users to continue using sanitized versions of 
libc++, this patch introduces a hack.
It adds a cribbed version of  the compiler-rt builtin to the libc++ filesystem 
sources.

I don't think this approach will work in the long run, but it seems OK for now.

Also see:

https://bugs.llvm.org/show_bug.cgi?id=30643
https://bugs.llvm.org/show_bug.cgi?id=16404


Repository:
  rCXX libc++

https://reviews.llvm.org/D49828

Files:
  src/experimental/filesystem/int128_builtins.cpp


Index: src/experimental/filesystem/int128_builtins.cpp
===
--- /dev/null
+++ src/experimental/filesystem/int128_builtins.cpp
@@ -0,0 +1,55 @@
+/*===-- int128_builtins.cpp - Implement __muloti4 --===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===--===
+ *
+ * This file implements __muloti4, and is stolen from the compiler_rt library.
+ *
+ * FIXME: we steal and re-compile it into filesystem, which uses __int128_t,
+ * and requires this builtin when sanitized. See llvm.org/PR30643
+ *
+ * ===--===
+ */
+#include "__config"
+#include "climits"
+
+#ifndef _LIBCPP_HAS_NO_INT128
+
+__attribute__((no_sanitize("undefined"))) extern "C" __int128_t
+__muloti4(__int128_t a, __int128_t b, int* overflow) {
+  const int N = (int)(sizeof(__int128_t) * CHAR_BIT);
+  const __int128_t MIN = (__int128_t)1 << (N - 1);
+  const __int128_t MAX = ~MIN;
+  *overflow = 0;
+  __int128_t result = a * b;
+  if (a == MIN) {
+if (b != 0 && b != 1)
+  *overflow = 1;
+return result;
+  }
+  if (b == MIN) {
+if (a != 0 && a != 1)
+  *overflow = 1;
+return result;
+  }
+  __int128_t sa = a >> (N - 1);
+  __int128_t abs_a = (a ^ sa) - sa;
+  __int128_t sb = b >> (N - 1);
+  __int128_t abs_b = (b ^ sb) - sb;
+  if (abs_a < 2 || abs_b < 2)
+return result;
+  if (sa == sb) {
+if (abs_a > MAX / abs_b)
+  *overflow = 1;
+  } else {
+if (abs_a > MIN / -abs_b)
+  *overflow = 1;
+  }
+  return result;
+}
+
+#endif


Index: src/experimental/filesystem/int128_builtins.cpp
===
--- /dev/null
+++ src/experimental/filesystem/int128_builtins.cpp
@@ -0,0 +1,55 @@
+/*===-- int128_builtins.cpp - Implement __muloti4 --===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===--===
+ *
+ * This file implements __muloti4, and is stolen from the compiler_rt library.
+ *
+ * FIXME: we steal and re-compile it into filesystem, which uses __int128_t,
+ * and requires this builtin when sanitized. See llvm.org/PR30643
+ *
+ * ===--===
+ */
+#include "__config"
+#include "climits"
+
+#ifndef _LIBCPP_HAS_NO_INT128
+
+__attribute__((no_sanitize("undefined"))) extern "C" __int128_t
+__muloti4(__int128_t a, __int128_t b, int* overflow) {
+  const int N = (int)(sizeof(__int128_t) * CHAR_BIT);
+  const __int128_t MIN = (__int128_t)1 << (N - 1);
+  const __int128_t MAX = ~MIN;
+  *overflow = 0;
+  __int128_t result = a * b;
+  if (a == MIN) {
+if (b != 0 && b != 1)
+  *overflow = 1;
+return result;
+  }
+  if (b == MIN) {
+if (a != 0 && a != 1)
+  *overflow = 1;
+return result;
+  }
+  __int128_t sa = a >> (N - 1);
+  __int128_t abs_a = (a ^ sa) - sa;
+  __int128_t sb = b >> (N - 1);
+  __int128_t abs_b = (b ^ sb) - sb;
+  if (abs_a < 2 || abs_b < 2)
+return result;
+  if (sa == sb) {
+if (abs_a > MAX / abs_b)
+  *overflow = 1;
+  } else {
+if (abs_a > MIN / -abs_b)
+  *overflow = 1;
+  }
+  return result;
+}
+
+#endif
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49828: [libc++] Add hack to allow ubsan to work w/o compiler-rt (__muloti4 is undefined)

2018-07-25 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCXX337990: [libc++] Add hack to allow ubsan to work w/o 
compiler-rt (__muloti4 is… (authored by EricWF, committed by ).

Repository:
  rCXX libc++

https://reviews.llvm.org/D49828

Files:
  src/experimental/filesystem/int128_builtins.cpp


Index: src/experimental/filesystem/int128_builtins.cpp
===
--- src/experimental/filesystem/int128_builtins.cpp
+++ src/experimental/filesystem/int128_builtins.cpp
@@ -0,0 +1,55 @@
+/*===-- int128_builtins.cpp - Implement __muloti4 --===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===--===
+ *
+ * This file implements __muloti4, and is stolen from the compiler_rt library.
+ *
+ * FIXME: we steal and re-compile it into filesystem, which uses __int128_t,
+ * and requires this builtin when sanitized. See llvm.org/PR30643
+ *
+ * ===--===
+ */
+#include "__config"
+#include "climits"
+
+#ifndef _LIBCPP_HAS_NO_INT128
+
+__attribute__((no_sanitize("undefined"))) extern "C" __int128_t
+__muloti4(__int128_t a, __int128_t b, int* overflow) {
+  const int N = (int)(sizeof(__int128_t) * CHAR_BIT);
+  const __int128_t MIN = (__int128_t)1 << (N - 1);
+  const __int128_t MAX = ~MIN;
+  *overflow = 0;
+  __int128_t result = a * b;
+  if (a == MIN) {
+if (b != 0 && b != 1)
+  *overflow = 1;
+return result;
+  }
+  if (b == MIN) {
+if (a != 0 && a != 1)
+  *overflow = 1;
+return result;
+  }
+  __int128_t sa = a >> (N - 1);
+  __int128_t abs_a = (a ^ sa) - sa;
+  __int128_t sb = b >> (N - 1);
+  __int128_t abs_b = (b ^ sb) - sb;
+  if (abs_a < 2 || abs_b < 2)
+return result;
+  if (sa == sb) {
+if (abs_a > MAX / abs_b)
+  *overflow = 1;
+  } else {
+if (abs_a > MIN / -abs_b)
+  *overflow = 1;
+  }
+  return result;
+}
+
+#endif


Index: src/experimental/filesystem/int128_builtins.cpp
===
--- src/experimental/filesystem/int128_builtins.cpp
+++ src/experimental/filesystem/int128_builtins.cpp
@@ -0,0 +1,55 @@
+/*===-- int128_builtins.cpp - Implement __muloti4 --===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===--===
+ *
+ * This file implements __muloti4, and is stolen from the compiler_rt library.
+ *
+ * FIXME: we steal and re-compile it into filesystem, which uses __int128_t,
+ * and requires this builtin when sanitized. See llvm.org/PR30643
+ *
+ * ===--===
+ */
+#include "__config"
+#include "climits"
+
+#ifndef _LIBCPP_HAS_NO_INT128
+
+__attribute__((no_sanitize("undefined"))) extern "C" __int128_t
+__muloti4(__int128_t a, __int128_t b, int* overflow) {
+  const int N = (int)(sizeof(__int128_t) * CHAR_BIT);
+  const __int128_t MIN = (__int128_t)1 << (N - 1);
+  const __int128_t MAX = ~MIN;
+  *overflow = 0;
+  __int128_t result = a * b;
+  if (a == MIN) {
+if (b != 0 && b != 1)
+  *overflow = 1;
+return result;
+  }
+  if (b == MIN) {
+if (a != 0 && a != 1)
+  *overflow = 1;
+return result;
+  }
+  __int128_t sa = a >> (N - 1);
+  __int128_t abs_a = (a ^ sa) - sa;
+  __int128_t sb = b >> (N - 1);
+  __int128_t abs_b = (b ^ sb) - sb;
+  if (abs_a < 2 || abs_b < 2)
+return result;
+  if (sa == sb) {
+if (abs_a > MAX / abs_b)
+  *overflow = 1;
+  } else {
+if (abs_a > MIN / -abs_b)
+  *overflow = 1;
+  }
+  return result;
+}
+
+#endif
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45015: [Preprocessor] Allow libc++ to detect when aligned allocation is unavailable.

2018-08-03 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

Hi, I'm in the process of moving cities. please take over.

Thanks, and sorry


https://reviews.llvm.org/D45015



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


[PATCH] D50205: [libc++] Add availability markup for aligned new/delete

2018-08-03 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

How does this work when a user provides their own definitions? Does the 
attribute from the declaration still produce a warning? If so, then I think an 
in-compiler approach is better.


Repository:
  rCXX libc++

https://reviews.llvm.org/D50205



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


[PATCH] D42887: [Driver] Add option to manually control discarding value names in LLVM IR.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 5 inline comments as done.
EricWF added inline comments.



Comment at: lib/Driver/ToolChains/Clang.cpp:3269-3274
+  const bool IsAssertBuild =
 #ifdef NDEBUG
-  CmdArgs.push_back("-disable-llvm-verifier");
-  // Discard LLVM value names in -asserts builds.
-  CmdArgs.push_back("-discard-value-names");
+  false;
+#else
+  true;
 #endif

bogner wrote:
> It might be a few more characters, but I feel like this is more readable if 
> you put entire statements in the branches of the #if, ie:
> 
> #ifdef NDEBUG
>   const bool IsAssertBuild = false;
> #else
>   const bool IsAssertBuild = true;
> #endif
Ack. Done.



Comment at: test/Driver/clang_f_opts.c:522
+// RUN: %clang -### -S -fdiscard-value-names %s 2>&1 | FileCheck 
-check-prefix=CHECK-DISCARD-NAMES %s
+// RUN: %clang -### -S -fno-discard-value-names %s 2>&1 | FileCheck 
-check-prefix=CHECK-NO-DISCARD-NAMES %s
+// CHECK-DISCARD-NAMES: "-discard-value-names"

lebedev.ri wrote:
> I wonder if it is also possible to check that if neither of 
> `-f[no-]discard-value-names` is specified, what happens.
> The caveat is of course the asserts-vs-no-asserts build type.
I don't think so, at least not easily and without changes to the `lit` 
configuration.

It's gone untested this long, I would love to get this patch in without being 
responsible for adding those tests.



https://reviews.llvm.org/D42887



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


[PATCH] D42887: [Driver] Add option to manually control discarding value names in LLVM IR.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 133251.
EricWF marked an inline comment as done.
EricWF added a comment.

- Fix documentation as requested.
- Put entire statement inside of `#ifdef` blocks.


https://reviews.llvm.org/D42887

Files:
  docs/UsersManual.rst
  include/clang/Driver/Options.td
  lib/Driver/ToolChains/Clang.cpp
  test/Driver/clang_f_opts.c


Index: test/Driver/clang_f_opts.c
===
--- test/Driver/clang_f_opts.c
+++ test/Driver/clang_f_opts.c
@@ -517,3 +517,8 @@
 // RUN: %clang -### -S %s 2>&1 | FileCheck 
-check-prefix=CHECK-NO-CF-PROTECTION-BRANCH %s
 // CHECK-CF-PROTECTION-BRANCH: -fcf-protection=branch
 // CHECK-NO-CF-PROTECTION-BRANCH-NOT: -fcf-protection=branch
+
+// RUN: %clang -### -S -fdiscard-value-names %s 2>&1 | FileCheck 
-check-prefix=CHECK-DISCARD-NAMES %s
+// RUN: %clang -### -S -fno-discard-value-names %s 2>&1 | FileCheck 
-check-prefix=CHECK-NO-DISCARD-NAMES %s
+// CHECK-DISCARD-NAMES: "-discard-value-names"
+// CHECK-NO-DISCARD-NAMES-NOT: "-discard-value-names"
Index: lib/Driver/ToolChains/Clang.cpp
===
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -3266,13 +3266,24 @@
   if (!C.isForDiagnostics())
 CmdArgs.push_back("-disable-free");
 
-// Disable the verification pass in -asserts builds.
 #ifdef NDEBUG
-  CmdArgs.push_back("-disable-llvm-verifier");
-  // Discard LLVM value names in -asserts builds.
-  CmdArgs.push_back("-discard-value-names");
+  const bool IsAssertBuild = false;
+#else
+  const bool IsAssertBuild = true;
 #endif
 
+  // Disable the verification pass in -asserts builds.
+  if (!IsAssertBuild)
+CmdArgs.push_back("disable-llvm-verifier");
+
+  // Discard value names in assert builds unless otherwise specified.
+  if (const Arg *A = Args.getLastArg(options::OPT_fdiscard_value_names,
+ options::OPT_fno_discard_value_names)) {
+if (A->getOption().matches(options::OPT_fdiscard_value_names))
+  CmdArgs.push_back("-discard-value-names");
+  } else if (!IsAssertBuild)
+CmdArgs.push_back("-discard-value-names");
+
   // Set the main file name, so that debug info works even with
   // -save-temps.
   CmdArgs.push_back("-main-file-name");
Index: include/clang/Driver/Options.td
===
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -790,6 +790,10 @@
 HelpText<"Print a template comparison tree for differing templates">;
 def fdeclspec : Flag<["-"], "fdeclspec">, Group,
   HelpText<"Allow __declspec as a keyword">, Flags<[CC1Option]>;
+def fdiscard_value_names : Flag<["-"], "fdiscard-value-names">, 
Group,
+  HelpText<"Discard value names in LLVM IR">, Flags<[DriverOption]>;
+def fno_discard_value_names : Flag<["-"], "fno-discard-value-names">, 
Group,
+  HelpText<"Do not discard value names in LLVM IR">, Flags<[DriverOption]>;
 def fdollars_in_identifiers : Flag<["-"], "fdollars-in-identifiers">, 
Group,
   HelpText<"Allow '$' in identifiers">, Flags<[CC1Option]>;
 def fdwarf2_cfi_asm : Flag<["-"], "fdwarf2-cfi-asm">, 
Group;
Index: docs/UsersManual.rst
===
--- docs/UsersManual.rst
+++ docs/UsersManual.rst
@@ -1855,6 +1855,27 @@
   must come first.)
 
 
+Controlling LLVM IR Output
+--
+
+Controlling Value Names in LLVM IR
+^^
+
+Emitting value names in LLVM IR increases the size and verbosity of the IR.
+By default, value names are only emitted in assertion-enabled builds of Clang.
+However, when reading IR it can be useful to re-enable the emission of value
+names to improve readability.
+
+.. option:: -fdiscard-value-names
+
+  Discard value names when generating LLVM IR.
+
+.. option:: -fno-discard-value-names
+
+  Do not discard value names when generating LLVM IR. This option can be used
+  to re-enable names for release builds of Clang.
+
+
 Comment Parsing Options
 ---
 


Index: test/Driver/clang_f_opts.c
===
--- test/Driver/clang_f_opts.c
+++ test/Driver/clang_f_opts.c
@@ -517,3 +517,8 @@
 // RUN: %clang -### -S %s 2>&1 | FileCheck -check-prefix=CHECK-NO-CF-PROTECTION-BRANCH %s
 // CHECK-CF-PROTECTION-BRANCH: -fcf-protection=branch
 // CHECK-NO-CF-PROTECTION-BRANCH-NOT: -fcf-protection=branch
+
+// RUN: %clang -### -S -fdiscard-value-names %s 2>&1 | FileCheck -check-prefix=CHECK-DISCARD-NAMES %s
+// RUN: %clang -### -S -fno-discard-value-names %s 2>&1 | FileCheck -check-prefix=CHECK-NO-DISCARD-NAMES %s
+// CHECK-DISCARD-NAMES: "-discard-value-names"
+// CHECK-NO-DISCARD-NAMES-NOT: "-discard-value-names"
Index: lib/Driver/ToolChains/Clang.cpp
===
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/Too

[PATCH] D42887: [Driver] Add option to manually control discarding value names in LLVM IR.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC324498: [Driver] Add option to manually control discarding 
value names in LLVM IR. (authored by EricWF, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D42887

Files:
  docs/UsersManual.rst
  include/clang/Driver/Options.td
  lib/Driver/ToolChains/Clang.cpp
  test/Driver/clang_f_opts.c


Index: docs/UsersManual.rst
===
--- docs/UsersManual.rst
+++ docs/UsersManual.rst
@@ -1855,6 +1855,27 @@
   must come first.)
 
 
+Controlling LLVM IR Output
+--
+
+Controlling Value Names in LLVM IR
+^^
+
+Emitting value names in LLVM IR increases the size and verbosity of the IR.
+By default, value names are only emitted in assertion-enabled builds of Clang.
+However, when reading IR it can be useful to re-enable the emission of value
+names to improve readability.
+
+.. option:: -fdiscard-value-names
+
+  Discard value names when generating LLVM IR.
+
+.. option:: -fno-discard-value-names
+
+  Do not discard value names when generating LLVM IR. This option can be used
+  to re-enable names for release builds of Clang.
+
+
 Comment Parsing Options
 ---
 
Index: include/clang/Driver/Options.td
===
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -790,6 +790,10 @@
 HelpText<"Print a template comparison tree for differing templates">;
 def fdeclspec : Flag<["-"], "fdeclspec">, Group,
   HelpText<"Allow __declspec as a keyword">, Flags<[CC1Option]>;
+def fdiscard_value_names : Flag<["-"], "fdiscard-value-names">, 
Group,
+  HelpText<"Discard value names in LLVM IR">, Flags<[DriverOption]>;
+def fno_discard_value_names : Flag<["-"], "fno-discard-value-names">, 
Group,
+  HelpText<"Do not discard value names in LLVM IR">, Flags<[DriverOption]>;
 def fdollars_in_identifiers : Flag<["-"], "fdollars-in-identifiers">, 
Group,
   HelpText<"Allow '$' in identifiers">, Flags<[CC1Option]>;
 def fdwarf2_cfi_asm : Flag<["-"], "fdwarf2-cfi-asm">, 
Group;
Index: test/Driver/clang_f_opts.c
===
--- test/Driver/clang_f_opts.c
+++ test/Driver/clang_f_opts.c
@@ -517,3 +517,8 @@
 // RUN: %clang -### -S %s 2>&1 | FileCheck 
-check-prefix=CHECK-NO-CF-PROTECTION-BRANCH %s
 // CHECK-CF-PROTECTION-BRANCH: -fcf-protection=branch
 // CHECK-NO-CF-PROTECTION-BRANCH-NOT: -fcf-protection=branch
+
+// RUN: %clang -### -S -fdiscard-value-names %s 2>&1 | FileCheck 
-check-prefix=CHECK-DISCARD-NAMES %s
+// RUN: %clang -### -S -fno-discard-value-names %s 2>&1 | FileCheck 
-check-prefix=CHECK-NO-DISCARD-NAMES %s
+// CHECK-DISCARD-NAMES: "-discard-value-names"
+// CHECK-NO-DISCARD-NAMES-NOT: "-discard-value-names"
Index: lib/Driver/ToolChains/Clang.cpp
===
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -3266,13 +3266,24 @@
   if (!C.isForDiagnostics())
 CmdArgs.push_back("-disable-free");
 
-// Disable the verification pass in -asserts builds.
 #ifdef NDEBUG
-  CmdArgs.push_back("-disable-llvm-verifier");
-  // Discard LLVM value names in -asserts builds.
-  CmdArgs.push_back("-discard-value-names");
+  const bool IsAssertBuild = false;
+#else
+  const bool IsAssertBuild = true;
 #endif
 
+  // Disable the verification pass in -asserts builds.
+  if (!IsAssertBuild)
+CmdArgs.push_back("disable-llvm-verifier");
+
+  // Discard value names in assert builds unless otherwise specified.
+  if (const Arg *A = Args.getLastArg(options::OPT_fdiscard_value_names,
+ options::OPT_fno_discard_value_names)) {
+if (A->getOption().matches(options::OPT_fdiscard_value_names))
+  CmdArgs.push_back("-discard-value-names");
+  } else if (!IsAssertBuild)
+CmdArgs.push_back("-discard-value-names");
+
   // Set the main file name, so that debug info works even with
   // -save-temps.
   CmdArgs.push_back("-main-file-name");


Index: docs/UsersManual.rst
===
--- docs/UsersManual.rst
+++ docs/UsersManual.rst
@@ -1855,6 +1855,27 @@
   must come first.)
 
 
+Controlling LLVM IR Output
+--
+
+Controlling Value Names in LLVM IR
+^^
+
+Emitting value names in LLVM IR increases the size and verbosity of the IR.
+By default, value names are only emitted in assertion-enabled builds of Clang.
+However, when reading IR it can be useful to re-enable the emission of value
+names to improve readability.
+
+.. option:: -fdiscard-value-names
+
+  Discard value names when generating LLVM IR.
+
+.. option:: -fno-discard-value-names
+
+  Do not discard value names when generating LLVM IR. This option can be used
+  to re-enable names for re

[PATCH] D41223: [libc++] Fix PR35491 - std::array of zero-size doesn't work with non-default constructible types.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 133285.
EricWF added a comment.

- Update with new, hopefully working, version.


https://reviews.llvm.org/D41223

Files:
  include/__config
  include/array
  test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp
  test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp
  test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp
  test/std/containers/sequences/array/array.cons/default.pass.cpp
  test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp
  test/std/containers/sequences/array/array.data/data.pass.cpp
  test/std/containers/sequences/array/array.data/data_const.pass.cpp
  test/std/containers/sequences/array/array.fill/fill.fail.cpp
  test/std/containers/sequences/array/array.swap/swap.fail.cpp
  test/std/containers/sequences/array/at.pass.cpp
  test/std/containers/sequences/array/begin.pass.cpp
  test/std/containers/sequences/array/compare.fail.cpp
  test/std/containers/sequences/array/compare.pass.cpp
  test/std/containers/sequences/array/empty.fail.cpp
  test/std/containers/sequences/array/front_back.pass.cpp
  test/std/containers/sequences/array/indexing.pass.cpp
  test/std/containers/sequences/array/size_and_alignment.pass.cpp

Index: test/std/containers/sequences/array/size_and_alignment.pass.cpp
===
--- /dev/null
+++ test/std/containers/sequences/array/size_and_alignment.pass.cpp
@@ -0,0 +1,55 @@
+//===--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===--===//
+
+// 
+
+// template 
+// struct array
+
+// Test the size and alignment matches that of an array of a given type.
+
+#include 
+#include 
+#include 
+#include 
+
+#include "test_macros.h"
+
+template 
+void test() {
+  typedef T CArrayT[Size == 0 ? 1 : Size];
+  typedef std::array ArrayT;
+  static_assert(sizeof(CArrayT) == sizeof(ArrayT), "");
+  static_assert(TEST_ALIGNOF(CArrayT) == TEST_ALIGNOF(ArrayT), "");
+}
+
+template 
+void test_type() {
+  test();
+  test();
+  test();
+}
+
+struct TEST_ALIGNAS(TEST_ALIGNOF(std::max_align_t) * 2) TestType1 {
+
+};
+
+struct TEST_ALIGNAS(TEST_ALIGNOF(std::max_align_t) * 2) TestType2 {
+  char data[1000];
+};
+
+int main() {
+  test_type();
+  test_type();
+  test_type();
+  test_type();
+  test_type();
+  test_type();
+  test_type();
+}
Index: test/std/containers/sequences/array/indexing.pass.cpp
===
--- test/std/containers/sequences/array/indexing.pass.cpp
+++ test/std/containers/sequences/array/indexing.pass.cpp
@@ -56,7 +56,34 @@
 C::const_reference r2 = c[2];
 assert(r2 == 3.5);
 }
-
+{ // Test operator[] "works" on zero sized arrays
+typedef double T;
+typedef std::array C;
+C c = {};
+C const& cc = c;
+static_assert((std::is_same::value), "");
+static_assert((std::is_same::value), "");
+if (c.size() > (0)) { // always false
+  C::reference r1 = c[0];
+  C::const_reference r2 = cc[0];
+  ((void)r1);
+  ((void)r2);
+}
+}
+{ // Test operator[] "works" on zero sized arrays
+typedef double T;
+typedef std::array C;
+C c = {{}};
+C const& cc = c;
+static_assert((std::is_same::value), "");
+static_assert((std::is_same::value), "");
+if (c.size() > (0)) { // always false
+  C::reference r1 = c[0];
+  C::const_reference r2 = cc[0];
+  ((void)r1);
+  ((void)r2);
+}
+}
 #if TEST_STD_VER > 11
 {
 typedef double T;
Index: test/std/containers/sequences/array/front_back.pass.cpp
===
--- test/std/containers/sequences/array/front_back.pass.cpp
+++ test/std/containers/sequences/array/front_back.pass.cpp
@@ -64,7 +64,38 @@
 C::const_reference r2 = c.back();
 assert(r2 == 3.5);
 }
-
+{
+  typedef double T;
+  typedef std::array C;
+  C c = {};
+  C const& cc = c;
+  static_assert((std::is_same::value), "");
+  static_assert((std::is_same::value), "");
+  static_assert((std::is_same::value), "");
+  static_assert((std::is_same::value), "");
+  if (c.size() > (0)) { // always false
+TEST_IGNORE_NODISCARD c.front();
+TEST_IGNORE_NODISCARD c.back();
+TEST_IGNORE_NODISCARD cc.front();
+TEST_IGNORE_NODISCARD cc.back();
+  }
+}
+{
+  typedef double T;
+  typedef std::array C;
+  C c = {{}};
+  C const& cc = c;
+  static_assert((std::is_same::value), "");
+  static_assert((std::is_

[PATCH] D41223: [libc++] Fix PR35491 - std::array of zero-size doesn't work with non-default constructible types.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF reopened this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

This was reverted as it caused build failures. Re-opening with new version.


Repository:
  rCXX libc++

https://reviews.llvm.org/D41223



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


[PATCH] D41223: [libc++] Fix PR35491 - std::array of zero-size doesn't work with non-default constructible types.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.

Accepting new version.


https://reviews.llvm.org/D41223



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


[PATCH] D41223: [libc++] Fix PR35491 - std::array of zero-size doesn't work with non-default constructible types.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCXX324526: [libc++] Fix PR35491 - std::array of zero-size 
doesn't work with non-default… (authored by EricWF, committed by ).

Repository:
  rCXX libc++

https://reviews.llvm.org/D41223

Files:
  include/__config
  include/array
  test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp
  test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp
  test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp
  test/std/containers/sequences/array/array.cons/default.pass.cpp
  test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp
  test/std/containers/sequences/array/array.data/data.pass.cpp
  test/std/containers/sequences/array/array.data/data_const.pass.cpp
  test/std/containers/sequences/array/array.fill/fill.fail.cpp
  test/std/containers/sequences/array/array.swap/swap.fail.cpp
  test/std/containers/sequences/array/at.pass.cpp
  test/std/containers/sequences/array/begin.pass.cpp
  test/std/containers/sequences/array/compare.fail.cpp
  test/std/containers/sequences/array/compare.pass.cpp
  test/std/containers/sequences/array/empty.fail.cpp
  test/std/containers/sequences/array/front_back.pass.cpp
  test/std/containers/sequences/array/indexing.pass.cpp
  test/std/containers/sequences/array/size_and_alignment.pass.cpp

Index: include/array
===
--- include/array
+++ include/array
@@ -108,6 +108,8 @@
 #include 
 #include 
 #include 
+#include  // for _LIBCPP_UNREACHABLE
+#include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
@@ -117,6 +119,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+
 template 
 struct _LIBCPP_TEMPLATE_VIS array
 {
@@ -134,31 +137,27 @@
 typedef std::reverse_iterator   reverse_iterator;
 typedef std::reverse_iterator const_reverse_iterator;
 
-value_type __elems_[_Size > 0 ? _Size : 1];
+_Tp __elems_[_Size];
 
 // No explicit construct/copy/destroy for aggregate type
-_LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u)
-{_VSTD::fill_n(__elems_, _Size, __u);}
-_LIBCPP_INLINE_VISIBILITY
-void swap(array& __a) _NOEXCEPT_(_Size == 0 || __is_nothrow_swappable<_Tp>::value)
-{ __swap_dispatch((std::integral_constant()), __a); }
+_LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u) {
+  _VSTD::fill_n(__elems_, _Size, __u);
+}
 
 _LIBCPP_INLINE_VISIBILITY
-void __swap_dispatch(std::true_type, array&) {}
-
-_LIBCPP_INLINE_VISIBILITY
-void __swap_dispatch(std::false_type, array& __a)
-{ _VSTD::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);}
+void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) {
+  std::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);
+}
 
 // iterators:
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-iterator begin() _NOEXCEPT {return iterator(__elems_);}
+iterator begin() _NOEXCEPT {return iterator(data());}
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-const_iterator begin() const _NOEXCEPT {return const_iterator(__elems_);}
+const_iterator begin() const _NOEXCEPT {return const_iterator(data());}
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-iterator end() _NOEXCEPT {return iterator(__elems_ + _Size);}
+iterator end() _NOEXCEPT {return iterator(data() + _Size);}
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-const_iterator end() const _NOEXCEPT {return const_iterator(__elems_ + _Size);}
+const_iterator end() const _NOEXCEPT {return const_iterator(data() + _Size);}
 
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
 reverse_iterator rbegin() _NOEXCEPT {return reverse_iterator(end());}
@@ -184,7 +183,7 @@
 _LIBCPP_INLINE_VISIBILITY
 _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT {return _Size;}
 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
-_LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return _Size == 0;}
+_LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return false; }
 
 // element access:
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
@@ -197,15 +196,16 @@
 
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference front() {return __elems_[0];}
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference front() const {return __elems_[0];}
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference back()  {return __elems_[_Size > 0 ? _Size-1 : 0];}
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference back() const  {return __elems_[_Size > 0 ? _Size-1 : 0];}
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference back()  {return __elems_[_Size - 1];}
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_referenc

[PATCH] D41223: [libc++] Fix PR35491 - std::array of zero-size doesn't work with non-default constructible types.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL324526: [libc++] Fix PR35491 - std::array of zero-size 
doesn't work with non-default… (authored by EricWF, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D41223?vs=133285&id=133288#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D41223

Files:
  libcxx/trunk/include/__config
  libcxx/trunk/include/array
  
libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp
  
libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp
  
libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp
  libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp
  
libcxx/trunk/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp
  libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp
  
libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp
  libcxx/trunk/test/std/containers/sequences/array/array.fill/fill.fail.cpp
  libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.fail.cpp
  libcxx/trunk/test/std/containers/sequences/array/at.pass.cpp
  libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp
  libcxx/trunk/test/std/containers/sequences/array/compare.fail.cpp
  libcxx/trunk/test/std/containers/sequences/array/compare.pass.cpp
  libcxx/trunk/test/std/containers/sequences/array/empty.fail.cpp
  libcxx/trunk/test/std/containers/sequences/array/front_back.pass.cpp
  libcxx/trunk/test/std/containers/sequences/array/indexing.pass.cpp
  libcxx/trunk/test/std/containers/sequences/array/size_and_alignment.pass.cpp

Index: libcxx/trunk/include/__config
===
--- libcxx/trunk/include/__config
+++ libcxx/trunk/include/__config
@@ -793,8 +793,13 @@
 # if !defined(_LIBCPP_DEBUG)
 #   error cannot use _LIBCPP_DEBUG_USE_EXCEPTIONS unless _LIBCPP_DEBUG is defined
 # endif
-# define _NOEXCEPT_DEBUG noexcept(false)
-# define _NOEXCEPT_DEBUG_(x) noexcept(false)
+# ifdef _LIBCPP_HAS_NO_NOEXCEPT
+#   define _NOEXCEPT_DEBUG
+#   define _NOEXCEPT_DEBUG_(x)
+# else
+#   define _NOEXCEPT_DEBUG noexcept(false)
+#   define _NOEXCEPT_DEBUG_(x) noexcept(false)
+#endif
 #else
 # define _NOEXCEPT_DEBUG _NOEXCEPT
 # define _NOEXCEPT_DEBUG_(x) _NOEXCEPT_(x)
Index: libcxx/trunk/include/array
===
--- libcxx/trunk/include/array
+++ libcxx/trunk/include/array
@@ -108,6 +108,8 @@
 #include 
 #include 
 #include 
+#include  // for _LIBCPP_UNREACHABLE
+#include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
@@ -117,6 +119,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+
 template 
 struct _LIBCPP_TEMPLATE_VIS array
 {
@@ -134,31 +137,27 @@
 typedef std::reverse_iterator   reverse_iterator;
 typedef std::reverse_iterator const_reverse_iterator;
 
-value_type __elems_[_Size > 0 ? _Size : 1];
+_Tp __elems_[_Size];
 
 // No explicit construct/copy/destroy for aggregate type
-_LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u)
-{_VSTD::fill_n(__elems_, _Size, __u);}
-_LIBCPP_INLINE_VISIBILITY
-void swap(array& __a) _NOEXCEPT_(_Size == 0 || __is_nothrow_swappable<_Tp>::value)
-{ __swap_dispatch((std::integral_constant()), __a); }
+_LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u) {
+  _VSTD::fill_n(__elems_, _Size, __u);
+}
 
 _LIBCPP_INLINE_VISIBILITY
-void __swap_dispatch(std::true_type, array&) {}
-
-_LIBCPP_INLINE_VISIBILITY
-void __swap_dispatch(std::false_type, array& __a)
-{ _VSTD::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);}
+void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) {
+  std::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);
+}
 
 // iterators:
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-iterator begin() _NOEXCEPT {return iterator(__elems_);}
+iterator begin() _NOEXCEPT {return iterator(data());}
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-const_iterator begin() const _NOEXCEPT {return const_iterator(__elems_);}
+const_iterator begin() const _NOEXCEPT {return const_iterator(data());}
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-iterator end() _NOEXCEPT {return iterator(__elems_ + _Size);}
+iterator end() _NOEXCEPT {return iterator(data() + _Size);}
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-const_iterator end() const _NOEXCEPT {return const_iterator(__elems_ + _Size);}
+const_iterator end() const _NOEXCEPT {return const_iterator(data() + _Size);}
 
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
 reverse_iterator rbegin() _NOEXCEPT {return reverse_iterator(end());}
@@ -184,7 +183,7 @@
 _LIBCP

[PATCH] D40218: [Clang] Add __builtin_launder

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

Ping.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 133290.
EricWF added a comment.

- Rebase off master.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,71 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder(&fnp);
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo)  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *&fp,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(&const_int);
+static_assert(&const_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(&const_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(&i); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int &i) {
+  return (__builtin_launder(&i) == &i);
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `&i` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,21 @@
 
 return buf;
 }
+
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+  float *fd = __builtin_launder(fp);
+  __builtin_launder(fn); // expected-error {{function pointer argument to '__bu

[PATCH] D37035: Implement __builtin_LINE() et. al. to support source location capture.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 133294.
EricWF added reviewers: aaron.ballman, bogner, majnemer.
EricWF added a comment.

Ping.

- Rebase off trunk.


https://reviews.llvm.org/D37035

Files:
  docs/LanguageExtensions.rst
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/SourceLocExprScope.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Basic/TokenKinds.def
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ASTImporter.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Parse/ParseExpr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/builtin_FUNCTION.cpp
  test/CodeGenCXX/builtin_LINE.cpp
  test/CodeGenCXX/debug-info-line.cpp
  test/Parser/builtin_source_location.c
  test/Sema/source_location.c
  test/SemaCXX/Inputs/source-location-file.h
  test/SemaCXX/source_location.cpp

Index: test/SemaCXX/source_location.cpp
===
--- /dev/null
+++ test/SemaCXX/source_location.cpp
@@ -0,0 +1,475 @@
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify %s
+// expected-no-diagnostics
+
+#define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
+#define CURRENT_FROM_MACRO() SL::current()
+#define FORWARD(...) __VA_ARGS__
+
+namespace std {
+namespace experimental {
+struct source_location {
+private:
+  unsigned int __m_line = 0;
+  unsigned int __m_col = 0;
+  const char *__m_file = nullptr;
+  const char *__m_func = nullptr;
+public:
+  static constexpr source_location current(
+  const char *__file = __builtin_FILE(),
+  const char *__func = __builtin_FUNCTION(),
+  unsigned int __line = __builtin_LINE(),
+  unsigned int __col = __builtin_COLUMN()) noexcept {
+source_location __loc;
+__loc.__m_line = __line;
+__loc.__m_col = __col;
+__loc.__m_file = __file;
+__loc.__m_func = __func;
+return __loc;
+  }
+  constexpr source_location() = default;
+  constexpr source_location(source_location const &) = default;
+  constexpr unsigned int line() const noexcept { return __m_line; }
+  constexpr unsigned int column() const noexcept { return __m_col; }
+  constexpr const char *file() const noexcept { return __m_file; }
+  constexpr const char *function() const noexcept { return __m_func; }
+};
+} // namespace experimental
+} // namespace std
+
+using SL = std::experimental::source_location;
+
+#include "Inputs/source-location-file.h"
+namespace SLF = source_location_file;
+
+constexpr bool is_equal(const char *LHS, const char *RHS) {
+  while (*LHS != 0 && *RHS != 0) {
+if (*LHS != *RHS)
+  return false;
+++LHS;
+++RHS;
+  }
+  return *LHS == 0 && *RHS == 0;
+}
+
+template 
+constexpr T identity(T t) {
+  return t;
+}
+
+template 
+struct Pair {
+  T first;
+  U second;
+};
+
+template 
+constexpr bool is_same = false;
+template 
+constexpr bool is_same = true;
+
+// test types
+static_assert(is_same);
+static_assert(is_same);
+static_assert(is_same);
+static_assert(is_same);
+
+// test noexcept
+static_assert(noexcept(__builtin_LINE()));
+static_assert(noexcept(__builtin_COLUMN()));
+static_assert(noexcept(__builtin_FILE()));
+static_assert(noexcept(__builtin_FUNCTION()));
+
+//===--===//
+//__builtin_LINE()
+//===--===//
+
+namespace test_line {
+
+static_assert(SL::current().line() == __LINE__);
+static_assert(SL::current().line() == CURRENT_FROM_MACRO().line());
+
+static constexpr SL GlobalS = SL::current();
+
+static_assert(GlobalS.line() == __LINE__ - 2);
+
+// clang-format off
+constexpr bool test_line_fn() {
+  constexpr SL S = SL::current();
+  static_assert(S.line() == (__LINE__ - 1), "");
+  // The start of the call expression to `current()` begins at the token `SL`
+  constexpr int ExpectLine = __LINE__ + 3;
+  constexpr SL S2
+  =
+  SL // Call expression starts here
+  ::
+  current
+  (
+
+  )
+  ;
+  static_assert(S2.line() == ExpectLine, "");
+
+  static_assert(
+  FORWARD(
+ __builtin_LINE
+(
+)
+  )
+== __LINE__ - 1, "");
+  static_assert(\
+\
+  __builtin_LINE()\
+\
+  == __LINE__ - 2, "");
+  static_assert(\
+  _\
+_builtin_LINE()
+  == __LINE__ - 2, "");
+
+  return true;
+}
+// clang-format on
+static_assert(test_line_fn());
+
+

[PATCH] D42987: [libc++abi] fix compilation in C++17 mode

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF accepted this revision.
EricWF added a comment.
This revision is now accepted and ready to land.

I agree with Marshall. This should define 
`_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS` instead of 
`_LIBCPP_BUILDING_LIBRARY`. Other than that, this LGTM.


Repository:
  rCXXA libc++abi

https://reviews.llvm.org/D42987



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


[PATCH] D43047: [Builtins] Overload __builtin_operator_new/delete to accept an optional alignment parameter.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF created this revision.
EricWF added reviewers: rsmith, majnemer, aaron.ballman, erik.pilkington, 
bogner, ahatanak.

Libc++'s default allocator uses `__builtin_operator_new` and 
`__builtin_operator_delete` in order to allow the calls to new/delete to be 
ellided. However, libc++ now needs to support over-aligned types in the default 
allocator. In order to support this without disabling the existing optimization 
Clang needs to support calling the aligned new overloads from the builtins.

See llvm.org/PR22634 for more information about the libc++ bug.

This patch changes `__builtin_operator_new`/`__builtin_operator_delete` to 
allow passing an optional alignment parameter. The two parameter overloads will 
forward to the aligned versions of `operator new` and `operator delete`.

Additionally, libc++ needs a way to detect these new overloads. There seems to 
be no great way to do this. This patch chooses to add the feature check 
`has_aligned_builtin_operator_new`. Suggestions on how to better handle this 
case are very welcome!


https://reviews.llvm.org/D43047

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Lex/PPMacroExpansion.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGenCXX/new.cpp
  test/Lexer/has_feature_aligned_builtin_new.cpp
  test/SemaCXX/builtin-operator-new-delete-alignment-disabled.cpp
  test/SemaCXX/builtin-operator-new-delete.cpp

Index: test/SemaCXX/builtin-operator-new-delete.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-operator-new-delete.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -faligned-allocation -fsyntax-only -verify %s
+
+void *NP = 0;
+
+void test_signature() {
+  __builtin_operator_new();   // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_operator_new(0, 0, 0);// expected-error {{too many arguments to function call, expected 2, have 3}}
+  __builtin_operator_delete();// expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_operator_delete(0, 0, 0); // expected-error {{too many arguments to function call, expected 2, have 3}}
+}
+
+void test_typo_in_args() {
+  __builtin_operator_new(DNE);  // expected-error {{undeclared identifier 'DNE'}}
+  __builtin_operator_new(DNE, DNE2);// expected-error {{undeclared identifier 'DNE'}} expected-error {{'DNE2'}}
+  __builtin_operator_delete(DNE);   // expected-error {{'DNE'}}
+  __builtin_operator_delete(DNE, DNE2); // expected-error {{'DNE'}} expected-error {{'DNE2'}}
+}
+
+void test_arg_types() {
+  __builtin_operator_new(NP);// expected-error {{cannot initialize a parameter of type 'unsigned long' with an lvalue of type 'void *'}}
+  __builtin_operator_new(NP, 0); // expected-error {{cannot initialize a parameter of type 'unsigned long' with an lvalue of type 'void *'}}
+}
+
+void test_return_type() {
+  int w = __builtin_operator_new(42);// expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}}
+  int x = __builtin_operator_new(42, 42);// expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}}
+  int y = __builtin_operator_delete(NP); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}}
+  int z = __builtin_operator_delete(NP, 42); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}}
+}
Index: test/SemaCXX/builtin-operator-new-delete-alignment-disabled.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-operator-new-delete-alignment-disabled.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++03 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -faligned-allocation -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1z -fno-aligned-allocation -fsyntax-only -verify %s
+
+void test_disabled() {
+#ifdef __cpp_aligned_new
+  // expected-no-diagnostics
+#else
+  // expected-error@+3 {{__builtin_operator_new with alignment requires aligned allocation support; use -faligned-allocation to enable}}
+  // expected-error@+3 {{__builtin_operator_delete with alignment requires aligned allocation support; use -faligned-allocation to enable}}
+#endif
+  (void)__builtin_operator_new(1, 2);
+  __builtin_operator_delete((void *)0, 2);
+}
Index: test/Lexer/has_feature_aligned_builtin_new.cpp
===
--- /dev/null
+++ test/Lexer/has_feature_aligned_builtin_new.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=c++11 %s -o - | \
+// RUN:   FileCheck --check-prefix=CHECK-NO-BUILTIN %s
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std

[PATCH] D43047: [Builtins] Overload __builtin_operator_new/delete to accept an optional alignment parameter.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked an inline comment as done.
EricWF added inline comments.



Comment at: lib/CodeGen/CGExprCXX.cpp:1309-1344
 RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
- const Expr *Arg,
- bool IsDelete) {
+ const Expr *E, bool IsDelete) 
{
+  const auto *TheCall = dyn_cast(E);
+  llvm::SmallVector ArgTypes;
+  for (auto *Arg : TheCall->arguments())
+ArgTypes.push_back(Arg->getType());
   CallArgList Args;

rsmith wrote:
> Can we leave this code alone and set the builtin expression's type to exactly 
> match the type of the chosen function? I really don't want to be 
> special-casing aligned allocation here. (This change should also cover sized 
> delete and any future extensions to builtin operator new/delete.)
That doesn't seem possible as you describe it. Both overloads of the builtin 
operator share the same `FunctionDecl`, and we can't change the type of that 
decl to match the selected operator for a particular call.

I think checking the argument types is the best way to proceed. However, I'll 
change the types of the call expression to exactly match the types of the 
selected `operator new/delete`, which will at least clean this up some.


https://reviews.llvm.org/D43047



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


[PATCH] D43047: [Builtins] Overload __builtin_operator_new/delete to accept an optional alignment parameter.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added inline comments.



Comment at: lib/CodeGen/CGExprCXX.cpp:1309-1344
 RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
- const Expr *Arg,
- bool IsDelete) {
+ const Expr *E, bool IsDelete) 
{
+  const auto *TheCall = dyn_cast(E);
+  llvm::SmallVector ArgTypes;
+  for (auto *Arg : TheCall->arguments())
+ArgTypes.push_back(Arg->getType());
   CallArgList Args;

EricWF wrote:
> rsmith wrote:
> > Can we leave this code alone and set the builtin expression's type to 
> > exactly match the type of the chosen function? I really don't want to be 
> > special-casing aligned allocation here. (This change should also cover 
> > sized delete and any future extensions to builtin operator new/delete.)
> That doesn't seem possible as you describe it. Both overloads of the builtin 
> operator share the same `FunctionDecl`, and we can't change the type of that 
> decl to match the selected operator for a particular call.
> 
> I think checking the argument types is the best way to proceed. However, I'll 
> change the types of the call expression to exactly match the types of the 
> selected `operator new/delete`, which will at least clean this up some.
Nevermind... I see what you meant. I can set the `Callee` type and not the type 
of the `CalleeDecl`.


https://reviews.llvm.org/D43047



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


[PATCH] D43047: [Builtins] Overload __builtin_operator_new/delete to accept an optional alignment parameter.

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 133365.
EricWF added a comment.

@rsmith Is this the direction you were thinking?

I haven't updated the tests yet, but I wanted to make the other changes visible 
earlier.


https://reviews.llvm.org/D43047

Files:
  include/clang/Basic/Builtins.def
  include/clang/Sema/Sema.h
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Lex/PPMacroExpansion.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaExprCXX.cpp
  test/CodeGenCXX/new.cpp
  test/Preprocessor/builtin_operator_new_delete.cpp
  test/SemaCXX/builtin-operator-new-delete-alignment-disabled.cpp
  test/SemaCXX/builtin-operator-new-delete.cpp

Index: test/SemaCXX/builtin-operator-new-delete.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-operator-new-delete.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -faligned-allocation -fsyntax-only -verify %s
+
+void *NP = 0;
+
+void test_signature() {
+  __builtin_operator_new();   // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_operator_new(0, 0, 0);// expected-error {{too many arguments to function call, expected 2, have 3}}
+  __builtin_operator_delete();// expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_operator_delete(0, 0, 0); // expected-error {{too many arguments to function call, expected 2, have 3}}
+}
+
+void test_typo_in_args() {
+  __builtin_operator_new(DNE);  // expected-error {{undeclared identifier 'DNE'}}
+  __builtin_operator_new(DNE, DNE2);// expected-error {{undeclared identifier 'DNE'}} expected-error {{'DNE2'}}
+  __builtin_operator_delete(DNE);   // expected-error {{'DNE'}}
+  __builtin_operator_delete(DNE, DNE2); // expected-error {{'DNE'}} expected-error {{'DNE2'}}
+}
+
+void test_arg_types() {
+  __builtin_operator_new(NP);// expected-error {{cannot initialize a parameter of type 'unsigned long' with an lvalue of type 'void *'}}
+  __builtin_operator_new(NP, 0); // expected-error {{cannot initialize a parameter of type 'unsigned long' with an lvalue of type 'void *'}}
+}
+
+void test_return_type() {
+  int w = __builtin_operator_new(42);// expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}}
+  int x = __builtin_operator_new(42, 42);// expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}}
+  int y = __builtin_operator_delete(NP); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}}
+  int z = __builtin_operator_delete(NP, 42); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}}
+}
Index: test/SemaCXX/builtin-operator-new-delete-alignment-disabled.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-operator-new-delete-alignment-disabled.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++03 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -faligned-allocation -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1z -fno-aligned-allocation -fsyntax-only -verify %s
+
+void test_disabled() {
+#ifdef __cpp_aligned_new
+  // expected-no-diagnostics
+#else
+  // expected-error@+3 {{__builtin_operator_new with alignment requires aligned allocation support; use -faligned-allocation to enable}}
+  // expected-error@+3 {{__builtin_operator_delete with alignment requires aligned allocation support; use -faligned-allocation to enable}}
+#endif
+  (void)__builtin_operator_new(1, 2);
+  __builtin_operator_delete((void *)0, 2);
+}
Index: test/Preprocessor/builtin_operator_new_delete.cpp
===
--- /dev/null
+++ test/Preprocessor/builtin_operator_new_delete.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 %s -fsyntax-only -verify
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 %s -fsyntax-only -verify
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 %s -fsyntax-only -verify
+
+// expected-no-diagnostics
+
+#if __has_builtin(__builtin_operator_new) != __has_builtin(__builtin_operator_delete)
+#error builtins should report same value
+#endif
+
+#if !__has_builtin(__builtin_operator_new) || !__has_builtin(__builtin_operator_delete)
+#error builtins should always be available
+#endif
+
+#if __has_builtin(__builtin_operator_new) != 201802L || \
+__has_builtin(__builtin_operator_delete) != 201802L
+#error builtin should report updated value
+#endif
+
Index: test/CodeGenCXX/new.cpp
===
--- test/CodeGenCXX/new.cpp
+++ test/CodeGenCXX/new.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unkn

[PATCH] D42987: [libc++abi] fix compilation in C++17 mode

2018-02-08 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

@rsmith. Sorry, you're right. I didn't notice that we already used 
`_LIBCPP_BUILDING_LIBRARY` in libc++abi.  I wasn't sure if `_BUILDING_LIBRARY` 
changed the linkage or of any symbols, or changed their explicit instantiation.
And, indeed, on Windows there's a problem with DLL import/export macros. I'll 
fix and cleanup the usage of `_BUILDING_LIBRARY` in the next couple days.


Repository:
  rL LLVM

https://reviews.llvm.org/D42987



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


[PATCH] D43047: [Builtins] Overload __builtin_operator_new/delete to allow forwarding to usual allocation/deallocation functions.

2018-02-08 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 133517.
EricWF retitled this revision from "[Builtins] Overload 
__builtin_operator_new/delete to accept an optional alignment parameter." to 
"[Builtins] Overload __builtin_operator_new/delete to allow forwarding to usual 
allocation/deallocation functions.".
EricWF edited the summary of this revision.
EricWF added a comment.

- Complete implementation suggested by @rsmith. The builtins now perform 
overload resolution to allow calling arbitrary usual allocation/deallocation 
functions.
- Complete tests.


https://reviews.llvm.org/D43047

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Lex/PPMacroExpansion.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaExprCXX.cpp
  test/CodeGenCXX/builtin-operator-new-delete.cpp
  test/SemaCXX/builtin-operator-new-delete.cpp

Index: test/SemaCXX/builtin-operator-new-delete.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-operator-new-delete.cpp
@@ -0,0 +1,153 @@
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++03 -faligned-allocation -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fsized-deallocation %s
+
+#if !__has_builtin(__builtin_operator_new) || !__has_builtin(__builtin_operator_delete)
+#error builtins should always be available
+#endif
+
+#if __has_builtin(__builtin_operator_new) != 201802L || \
+__has_builtin(__builtin_operator_delete) != 201802L
+#error builtin should report updated value
+#endif
+
+typedef __SIZE_TYPE__ size_t;
+namespace std {
+  struct nothrow_t {};
+#if __cplusplus >= 201103L
+enum class align_val_t : size_t {};
+#else
+  enum align_val_t { __zero = 0,
+ __max = (size_t)-1 };
+#endif
+}
+std::nothrow_t nothrow;
+
+void *operator new(size_t); // expected-note 1+ {{candidate function}}
+void operator delete(void *); // expected-note 1+ {{candidate function}}
+
+// Declare the reserved placement operators.
+void *operator new(size_t, void*) throw(); // expected-note 1+ {{candidate function}}
+void operator delete(void *, void *)throw(); // expected-note 1+ {{candidate function}}
+void *operator new[](size_t, void*) throw();
+void operator delete[](void*, void*) throw();
+
+// Declare the replaceable global allocation operators.
+void *operator new(size_t, const std::nothrow_t &) throw(); // expected-note 1+ {{candidate function}}
+void *operator new[](size_t, const std::nothrow_t &) throw();
+void operator delete(void *, const std::nothrow_t &)throw(); // expected-note 1+ {{candidate function}}
+void operator delete[](void *, const std::nothrow_t &) throw();
+
+// aligned allocation and deallocation functions.
+void* operator new  ( size_t count, std::align_val_t al); // expected-note 1+ {{candidate function}}
+void operator delete(void *, std::align_val_t); // expected-note 1+ {{candidate}}
+#ifndef __cpp_aligned_new
+// expected-note@-3 1+ {{non-usual 'operator new' declared here}}
+// expected-note@-3 1+ {{non-usual 'operator delete' declared here}}
+#endif
+void *operator new[](size_t count, std::align_val_t al);
+void operator delete[](void*, std::align_val_t);
+
+void operator delete(void *, size_t); // expected-note 1+ {{candidate}}
+#ifndef __cpp_sized_deallocation
+// expected-note@-2 1+ {{non-usual 'operator delete' declared here}}
+#endif
+void operator delete[](void*, size_t);
+
+// Declare some other placemenet operators.
+void *operator new(size_t, void*, bool) throw(); // expected-note 1+ {{candidate function}}
+void *operator new[](size_t, void*, bool) throw();
+
+void *NP = 0;
+
+void test_typo_in_args() {
+  __builtin_operator_new(DNE);  // expected-error {{undeclared identifier 'DNE'}}
+  __builtin_operator_new(DNE, DNE2);// expected-error {{undeclared identifier 'DNE'}} expected-error {{'DNE2'}}
+  __builtin_operator_delete(DNE);   // expected-error {{'DNE'}}
+  __builtin_operator_delete(DNE, DNE2); // expected-error {{'DNE'}} expected-error {{'DNE2'}}
+}
+
+void test_arg_types() {
+  __builtin_operator_new(NP);  // expected-error {{no matching function for call to 'operator new'}}
+  __builtin_operator_new(NP, std::align_val_t(0)); // expected-error {{no matching function for call to 'operator new'}}}
+}
+void test_return_type() {
+  int w = __builtin_operator_new(42);// expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}}
+  int y = __builtin_operator_delete(NP); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}}
+}
+
+void test_aligned_new() {
+#ifdef __cpp_aligned_new
+  void *p = __builtin_operator_new(42, std::align_val_t(2));
+  __bu

[PATCH] D42344: [libc++] Use multi-key tree search for {map, set}::{count, equal_range}

2018-02-08 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

This LGTM.


https://reviews.llvm.org/D42344



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


[PATCH] D41316: [libcxx] Allow random_device to be built optionally

2018-02-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

I think the direction here is OK. Although I really hate allowing bits of 
libc++ to be "optional". In this case it should be OK, but often it makes the 
library trickier to maintain -- and these configurations often go untested 
between releases.




Comment at: CMakeLists.txt:74
 option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS})
+option(LIBCXX_ENABLE_RANDOM_DEVICE "Build random_device class" On)
 

nit: `ON`



Comment at: test/std/experimental/filesystem/lit.local.cfg:5
+
+# filesystem_test_helper uses random_device to generate random path.
+if 'libcpp-has-no-random-device' in config.available_features:

I would rather keep these tests running using a different source for the random 
seed if possible.



Comment at: test/std/numerics/rand/rand.device/lit.local.cfg:1
+# Disable all of the random device tests if the correct feature is not 
available.
+if 'libcpp-has-no-random-device' in config.available_features:

There are only 3 tests under this directory. I would rather mark each one 
explicitly with `// UNSUPPORTED: libcpp-has-no-random-device`


Repository:
  rCXX libc++

https://reviews.llvm.org/D41316



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


[PATCH] D41316: [libcxx] Allow random_device to be built optionally

2018-02-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added inline comments.



Comment at: test/std/experimental/filesystem/lit.local.cfg:5
+
+# filesystem_test_helper uses random_device to generate random path.
+if 'libcpp-has-no-random-device' in config.available_features:

EricWF wrote:
> I would rather keep these tests running using a different source for the 
> random seed if possible.
Perhaps the random generator could be initialized using 
`std::chrono::system_clock::now().time_since_epoch().count()`, which should 
produce more distinct values that the typical `time(NULL)` method used to 
initialize `srand`.


Repository:
  rCXX libc++

https://reviews.llvm.org/D41316



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


  1   2   3   4   5   6   7   8   9   10   >