[PATCH] D21767: Fix instantiation of friend function templates

2018-08-12 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 160290.
sepavloff added a comment.

Rebased the patch, it is still actual.


Repository:
  rC Clang

https://reviews.llvm.org/D21767

Files:
  include/clang/AST/ASTLambda.h
  include/clang/AST/Decl.h
  include/clang/Sema/Sema.h
  lib/AST/Decl.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaTemplate/instantiate-friend-function.cpp

Index: test/SemaTemplate/instantiate-friend-function.cpp
===
--- test/SemaTemplate/instantiate-friend-function.cpp
+++ test/SemaTemplate/instantiate-friend-function.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -S -triple %itanium_abi_triple -std=c++11 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -S -triple %itanium_abi_triple -std=c++11 -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s
 // expected-no-diagnostics
 
 namespace PR10856 {
@@ -47,3 +47,572 @@
 
 // bool PR10856_Root::g, void>(PR10856_Root::MyClass)
 // CHECK: call {{.*}} @_ZN12PR10856_Root1gINS_7MyClassIiEEvEEbT_
+
+// Instantiate friend function, pattern is at file level.
+
+
+template struct C01 {
+  template friend void func_01(C01 &, T1);
+  template friend void func_01a(C01 &, T2);
+};
+
+C01 c01;
+
+void f_01() {
+  func_01(c01, 0.0);
+  func_01a(c01, 0.0);
+}
+
+template void func_01(C01 &, T1) {}
+template void func_01a(C01 &, T2) {}
+
+// void func_01(C01&, double)
+// CHECK: define linkonce_odr void @_Z7func_01IdEvR3C01IiET_
+//
+// void func_01a(C01&, double)
+// CHECK: define linkonce_odr void @_Z8func_01aIidEvR3C01IT_ET0_
+
+
+template struct C02 {
+  template friend void func_02(const C02 &, T1) { T var; }
+  template friend void func_02a(const C02 &, T2) { T var; }
+  template friend constexpr unsigned func_02b(const C02 &, const T1 x) { return sizeof(T1); }
+};
+
+const C02 c02;
+
+void f_02() {
+  func_02(c02, 0.0);
+  func_02a(c02, 0.0);
+  static_assert(func_02b(c02, short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_02b(c02, 122L) == sizeof(long), "Invalid calculation");
+}
+
+// void func_02(C02 const&, double)
+// CHECK: define linkonce_odr void @_Z7func_02IdEvRK3C02IiET_
+//
+// void func_02a(C02 const&, double)
+// CHECK: define linkonce_odr void @_Z8func_02aIidEvRK3C02IT_ET0_
+
+
+template struct C03 {
+  template friend void func_03(C03 &, T1);
+  template friend void func_03a(C03 &, T2);
+};
+
+C03 c03;
+
+void f_03() {
+  func_03(c03, 0.0);
+  func_03a(c03, 0.0);
+}
+
+template struct C03A {
+  template friend void func_03(C03 &, T1) { }
+};
+template struct C03B {
+  template friend void func_03a(C03 &, T2) { T var; }
+};
+
+C03A c03a;
+C03B c03b;
+
+// void func_03(C03&, double)
+// CHECK: define linkonce_odr void @_Z7func_03IdEvR3C03IiET_
+//
+// void func_03a(C03&, double)
+// CHECK: define linkonce_odr void @_Z8func_03aIidEvR3C03IT_ET0_
+
+
+// File level declaration, friend pattern.
+
+
+template void func_10(T1 *x);
+template void func_10a(T1 *x, T2 *y);
+template constexpr unsigned func_10b(const T1 x);
+template constexpr unsigned func_10c(const T1 x);
+
+template
+struct C10 {
+  template friend void func_10(T1 *x) { T var; }
+  template friend void func_10a(T1 *x, T2 *y) { T var; }
+  template friend constexpr unsigned func_10b(const T1 x) { return sizeof(T1); }
+  template friend constexpr unsigned func_10c(const T1 x) { return sizeof(T); }
+};
+
+C10 v10;
+
+void use_10(int *x) {
+  func_10(x);
+  func_10a(x, &x);
+  static_assert(func_10b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_10b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_10c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_10c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_10(int*)
+// CHECK: define linkonce_odr void @_Z7func_10IiEvPT_
+//
+// void func_10a(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_10aIiPiEvPT_PT0_
+
+
+template
+struct C11 {
+  template friend void func_11(T1 *x) { T var; }
+  template friend void func_11a(T1 *x, T2 *y) { T var; }
+  template friend constexpr unsigned func_11b(const T1 x) { return sizeof(T1); }
+  template friend constexpr unsigned func_11c(const T1 x) { return sizeof(T); }
+};
+
+C11 v11;
+
+template void func_11(T *x);
+template void func_11a(T1 *x, T2 *y);
+template constexpr unsigned func_11b(const T1 x);
+template constexpr unsigned func_11c(const T1 x);
+
+void use_11(int *x) {
+  func_11(x);
+  func_11a(x, &x);
+  static_assert(func_11b(short(123)) == sizeof(short), "Invalid calculation");
+  static_assert(func_11b(123L) == sizeof(long), "Invalid calculation");
+  static_assert(func_11c(short(123)) == sizeof(int), "Invalid calculation");
+  static_assert(func_11c(123L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_11(int*)
+// CHECK: define lin

[PATCH] D21508: Diagnose friend function template redefinitions

2018-08-13 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 160298.
sepavloff added a comment.

Rebased the patch


Repository:
  rC Clang

https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/Modules/friend-definition.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
Index: test/Modules/friend-definition.cpp
===
--- test/Modules/friend-definition.cpp
+++ test/Modules/friend-definition.cpp
@@ -7,6 +7,7 @@
 #pragma clang module begin A
 template struct A {
   friend A operator+(const A&, const A&) { return {}; }
+  template friend void func_1(const A&, const T2 &) {}
 };
 #pragma clang module end
 #pragma clang module endbuild
@@ -36,4 +37,5 @@
 void h() {
   A a;
   a + a;
+  func_1(a, 0);
 }
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1793,7 +1793,9 @@
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-PrincipalDecl->setObjectOfFriendDecl();
+Function->setObjectOfFriendDecl();
+if (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate())
+  FT->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12654,6 +12654,29 @@
   }
 }
   }
+
+  if (!Definition)
+// Similar to friend functions a friend function template may be a
+// definition and do not have a body if it is instantiated in a class
+// template.
+if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) {
+  for (auto I : FTD->redecls()) {
+auto D = cast(I);
+if (D != FTD) {
+  assert(!D->isThisDeclarationADefinition() &&
+ "More than one definition in redeclaration chain");
+  if (D->getFriendObjectKind() != Decl::FOK_None)
+if (FunctionTemplateDecl *FT =
+   D->getInstantiatedFromMemberTemplate()) {
+  if (FT->isThisDeclarationADefinition()) {
+Definition = D->getTemplatedDecl();
+break;
+  }
+}
+}
+  }
+}
+
   if (!Definition)
 return;
 
Index: include/clang/AST/DeclBase.h
===
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -1078,11 +1078,11 @@
 unsigned OldNS = IdentifierNamespace;
 assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
  IDNS_TagFriend | IDNS_OrdinaryFr

[PATCH] D21767: Fix instantiation of friend function templates

2018-08-14 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

In https://reviews.llvm.org/D21767#1197783, @rjmccall wrote:

> Shouldn't there just be a link in the AST from the instantiated 
> `FunctionTemplateDecl ` back to the original pattern?  Maybe a generalization 
> of `InstantiatedFromMember` in `RedeclarablableTemplateDecl`?


The field `InstantiatedFromMember` indeed helps finding function template 
definition, this patch only modifies search algorithm to make it suitable for 
friend templates. Friend function templates have dual nature, they may be 
members of redeclaration chains, like usual namespace level function templates 
and still use `InstantiatedFromMember` like member function templates. So the 
resulting search algorithm (implemented in `getPatternFor`) scans both 
redeclaration chain and the chain formed by `InstantiatedFromMember`.


Repository:
  rC Clang

https://reviews.llvm.org/D21767



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


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-08 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 145735.
sepavloff added a comment.

Added treatment of structures/unions


Repository:
  rC Clang

https://reviews.llvm.org/D46241

Files:
  include/clang/AST/Expr.h
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGen/const-init.c
  test/CodeGen/designated-initializers.c
  test/CodeGen/union-init2.c
  test/CodeGenCXX/cxx11-initializer-aggregate.cpp
  test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
  test/SemaCXX/large-array-init.cpp

Index: test/SemaCXX/large-array-init.cpp
===
--- test/SemaCXX/large-array-init.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -S -o %t.ll -mllvm -debug-only=exprconstant %s 2>&1 | \
-// RUN: FileCheck %s
-// REQUIRES: asserts
-
-struct S { int i; };
-
-static struct S arr[1] = {{ 0 }};
-// CHECK: The number of elements to initialize: 1.
-
-struct S *foo() { return arr; }
Index: test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
@@ -17,14 +17,14 @@
 
   C c1 = {};
   C c2 = {1};
-  // CHECK: @_ZN8Constant2c1E = global { i8 } zeroinitializer, align 1
+  // CHECK: @_ZN8Constant2c1E = global %"struct.Constant::C" zeroinitializer, align 1
   // CHECK: @_ZN8Constant2c2E = global { i8 } { i8 1 }, align 1
 
   // Test packing bases into tail padding.
   D d1 = {};
   D d2 = {1, 2, 3};
   D d3 = {1};
-  // CHECK: @_ZN8Constant2d1E = global { i32, i8, i8 } zeroinitializer, align 4
+  // CHECK: @_ZN8Constant2d1E = global %"struct.Constant::D" zeroinitializer, align 4
   // CHECK: @_ZN8Constant2d2E = global { i32, i8, i8 } { i32 1, i8 2, i8 3 }, align 4
   // CHECK: @_ZN8Constant2d3E = global { i32, i8, i8 } { i32 1, i8 0, i8 0 }, align 4
 
Index: test/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,30 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+  constexpr int *null() { return nullptr; }
+  struct Filler {
+int x;
+Filler();
+  };
+  struct S1 {
+int x;
+  };
+
+  // These declarations, if implemented elementwise, require huge
+  // amout of memory and compiler time.
+  unsigned char data_1[1024 * 1024 * 1024 * 2u] = { 0 };
+  unsigned char data_2[1024 * 1024 * 1024 * 2u] = { Zero };
+  unsigned char data_3[1024][1024][1024] = {{{0}}};
+  unsigned char data_4[1024 * 1024 * 1024 * 2u] = { zero() };
+  int *data_5[1024 * 1024 * 512] = { nullptr };
+  int *data_6[1024 * 1024 * 512] = { null() };
+  struct S1 data_7[1024 * 1024 * 512] = {{0}};
+
+  // This variable must be initialized elementwise.
+  Filler data_e1[1024] = {};
+  // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
+}
Index: test/CodeGen/union-init2.c
===
--- test/CodeGen/union-init2.c
+++ test/CodeGen/union-init2.c
@@ -5,7 +5,7 @@
 union x {long long b;union x* a;} r = {.a = &r};
 
 
-// CHECK: global { [3 x i8], [5 x i8] } { [3 x i8] zeroinitializer, [5 x i8] undef }
+// CHECK: global %union.z zeroinitializer
 union z {
   char a[3];
   long long b;
Index: test/CodeGen/designated-initializers.c
===
--- test/CodeGen/designated-initializers.c
+++ test/CodeGen/designated-initializers.c
@@ -8,7 +8,7 @@
 // CHECK: @u = global %union.anon zeroinitializer
 union { int i; float f; } u = { };
 
-// CHECK: @u2 = global { i32, [4 x i8] } { i32 0, [4 x i8] undef }
+// CHECK: @u2 = global %union.anon.0 zeroinitializer
 union { int i; double f; } u2 = { };
 
 // CHECK: @u3 = global  %union.anon.1 zeroinitializer
Index: test/CodeGen/const-init.c
===
--- test/CodeGen/const-init.c
+++ test/CodeGen/const-init.c
@@ -167,7 +167,7 @@
 int : 1;
 int x;
   } a = {};
-  // CHECK: @g30.a = internal global %struct.anon.1 <{ i8 undef, i32 0 }>, align 1
+  // CHECK: @g30.a = internal global %struct.anon.1 zeroinitializer, align 1
 #pragma pack()
 }
 
Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,37 @@
   return type;
 }
 
+/// Checks if the specified initializer is equivalent to zero initialization.
+static bool isZeroInitializer(ConstantEmitter &CE, const Expr *Init) {
+  if (auto *E = dyn_cast_or_null(Init)) {
+CXXConstructorDecl *CD = E->getConstructor();
+return CD->isDefaultConstructor() && CD->isTrivial();
+  }
+
+  if (auto *IL = dyn_cast_or_null(Init)) {
+for (auto I : IL->inits())
+  if (!isZero

[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-08 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

> Hmm. In C++, a static object which isn't constant-initialized is 
> zero-initialized, which is required to set any padding bits to zero (N4640 
> [dcl.init]p6) in both structs and unions. In C, a static object which doesn't 
> have an initializer also has all any padding bits set to zero (N1548 
> 6.7.9p10). Now, this object has an initializer (that acts as a 
> constant-initializer in C++), so those rules don't directly apply; but I 
> would argue that the intent of the standards is not that padding bits become 
> undefined when you happen to have an initializer. So I actually think the 
> zeroinitializer emission is more correct.

Using undefined values instead of zero initialization was implemented in 
https://reviews.llvm.org/rL101535. There is no much info about the reason of 
the implementation. Clang uses undefined values for padding bits, in particular 
in unions, when the first member is not widest. The code:

  union C1 {
  char sel;
  double dval;
};
union C1 val_1 = { 0 };

produces:

  @val_1 = dso_local global { i8, [7 x i8] } { i8 0, [7 x i8] undef }, align 8  

Another case is unnamed bit fields.

struct C2 {
  int : 4;
  int x;
};
struct C2 val_2 = { 0 };

produces:

  @val_2 = dso_local global { [4 x i8], i32 } { [4 x i8] undef, i32 0 }, align 4

Strictly speaking, this IR does not mean violation of the standard, but it can 
modify code generation in some cases. If we decided to use zeroinitializer in 
this case, we probably would need to revise using undefined values in 
initializers, otherwise similar declarations like:

union C1 val_1a = { 0 };
union C1 val_1b = { 1 };

would produce different IR representations, with and without undefined values.

The test `SemaCXX/large-array-init.cpp` is removed in this change. This test 
was added in https://reviews.llvm.org/rL325120 to solve 
https://bugs.llvm.org/show_bug.cgi?id=18978, which describes the same problem, 
as solved by this patch. This patch presents more efficient solution, with it 
the tests compiles 50 time faster. If r325120 does not solve additional 
problems, it can be reverted.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



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


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-10 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 146091.
sepavloff added a comment.

Updated patch

Try evaluating initializer value only if the initializer type is
integral or pointer. It avoids calculation of large value, which
then is discarded.


Repository:
  rC Clang

https://reviews.llvm.org/D46241

Files:
  include/clang/AST/Expr.h
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGen/const-init.c
  test/CodeGen/designated-initializers.c
  test/CodeGen/union-init2.c
  test/CodeGenCXX/cxx11-initializer-aggregate.cpp
  test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
  test/SemaCXX/large-array-init.cpp

Index: test/SemaCXX/large-array-init.cpp
===
--- test/SemaCXX/large-array-init.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -S -o %t.ll -mllvm -debug-only=exprconstant %s 2>&1 | \
-// RUN: FileCheck %s
-// REQUIRES: asserts
-
-struct S { int i; };
-
-static struct S arr[1] = {{ 0 }};
-// CHECK: The number of elements to initialize: 1.
-
-struct S *foo() { return arr; }
Index: test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
@@ -17,14 +17,14 @@
 
   C c1 = {};
   C c2 = {1};
-  // CHECK: @_ZN8Constant2c1E = global { i8 } zeroinitializer, align 1
+  // CHECK: @_ZN8Constant2c1E = global %"struct.Constant::C" zeroinitializer, align 1
   // CHECK: @_ZN8Constant2c2E = global { i8 } { i8 1 }, align 1
 
   // Test packing bases into tail padding.
   D d1 = {};
   D d2 = {1, 2, 3};
   D d3 = {1};
-  // CHECK: @_ZN8Constant2d1E = global { i32, i8, i8 } zeroinitializer, align 4
+  // CHECK: @_ZN8Constant2d1E = global %"struct.Constant::D" zeroinitializer, align 4
   // CHECK: @_ZN8Constant2d2E = global { i32, i8, i8 } { i32 1, i8 2, i8 3 }, align 4
   // CHECK: @_ZN8Constant2d3E = global { i32, i8, i8 } { i32 1, i8 0, i8 0 }, align 4
 
Index: test/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,30 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+  constexpr int *null() { return nullptr; }
+  struct Filler {
+int x;
+Filler();
+  };
+  struct S1 {
+int x;
+  };
+
+  // These declarations, if implemented elementwise, require huge
+  // amout of memory and compiler time.
+  unsigned char data_1[1024 * 1024 * 1024 * 2u] = { 0 };
+  unsigned char data_2[1024 * 1024 * 1024 * 2u] = { Zero };
+  unsigned char data_3[1024][1024][1024] = {{{0}}};
+  unsigned char data_4[1024 * 1024 * 1024 * 2u] = { zero() };
+  int *data_5[1024 * 1024 * 512] = { nullptr };
+  int *data_6[1024 * 1024 * 512] = { null() };
+  struct S1 data_7[1024 * 1024 * 512] = {{0}};
+
+  // This variable must be initialized elementwise.
+  Filler data_e1[1024] = {};
+  // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
+}
Index: test/CodeGen/union-init2.c
===
--- test/CodeGen/union-init2.c
+++ test/CodeGen/union-init2.c
@@ -5,7 +5,7 @@
 union x {long long b;union x* a;} r = {.a = &r};
 
 
-// CHECK: global { [3 x i8], [5 x i8] } { [3 x i8] zeroinitializer, [5 x i8] undef }
+// CHECK: global %union.z zeroinitializer
 union z {
   char a[3];
   long long b;
Index: test/CodeGen/designated-initializers.c
===
--- test/CodeGen/designated-initializers.c
+++ test/CodeGen/designated-initializers.c
@@ -8,7 +8,7 @@
 // CHECK: @u = global %union.anon zeroinitializer
 union { int i; float f; } u = { };
 
-// CHECK: @u2 = global { i32, [4 x i8] } { i32 0, [4 x i8] undef }
+// CHECK: @u2 = global %union.anon.0 zeroinitializer
 union { int i; double f; } u2 = { };
 
 // CHECK: @u3 = global  %union.anon.1 zeroinitializer
Index: test/CodeGen/const-init.c
===
--- test/CodeGen/const-init.c
+++ test/CodeGen/const-init.c
@@ -167,7 +167,7 @@
 int : 1;
 int x;
   } a = {};
-  // CHECK: @g30.a = internal global %struct.anon.1 <{ i8 undef, i32 0 }>, align 1
+  // CHECK: @g30.a = internal global %struct.anon.1 zeroinitializer, align 1
 #pragma pack()
 }
 
Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,40 @@
   return type;
 }
 
+/// Checks if the specified initializer is equivalent to zero initialization.
+static bool isZeroInitializer(ConstantEmitter &CE, const Expr *Init) {
+  if (auto *E = dyn_cast_or_null(Init)) {
+CXXConstructorDecl *CD = E->getConstructor();
+return CD->isDefaultConstruc

[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-10 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1414-1415
+Expr::EvalResult Result;
+if (Init->EvaluateAsRValue(Result, CE.CGM.getContext()) &&
+!Result.hasUnacceptableSideEffect(Expr::SE_NoSideEffects))
+  return (Result.Val.isInt() && Result.Val.getInt().isNullValue()) ||

rsmith wrote:
> Please call `D.evaluateValue()` here rather than inventing your own 
> evaluation scheme. That way, we'll cache the evaluated initializer on the 
> variable for other uses or reuse the value if we've already evaluated it, and 
> you don't need to worry about the corner cases involved in getting the 
> evaluation right. (As it happens, you're getting some minor details wrong 
> because evaluating an initializer is not quite the same as evaluating an 
> rvalue, but in practice it's not a big deal here.)

Call of `D.evaluateValue()` may result in substantial memory and time 
consumption if the variable value is huge, like in:
```
int char data_1[2147483648u] = { 0 };
```
The idea of this patch is to recognize some cases of zero initialization prior 
to the evaluation of variable initializer. In the example above, value would be 
evaluated only for part of the initializer, namely `0`, which does not have an 
associated variable, so call of `D.evaluateValue()` is not possible.



Repository:
  rC Clang

https://reviews.llvm.org/D46241



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


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-15 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

@rsmith Do yo think this patch is OK to apply?


Repository:
  rC Clang

https://reviews.llvm.org/D46241



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


[PATCH] D44607: Recompute invalidated iterator in insertTargetAndModeArgs

2018-05-20 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

In https://reviews.llvm.org/D44607#1105962, @raj.khem wrote:

> Can this be backported to release_60 branch too please ?


The patch is compact, clear and addresses stability issue. I think it is worth 
of backporting to release_60.


Repository:
  rL LLVM

https://reviews.llvm.org/D44607



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


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-21 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC332847: [CodeGen] Recognize more cases of zero 
initialization (authored by sepavloff, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D46241?vs=146091&id=147798#toc

Repository:
  rC Clang

https://reviews.llvm.org/D46241

Files:
  include/clang/AST/Expr.h
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGen/const-init.c
  test/CodeGen/designated-initializers.c
  test/CodeGen/union-init2.c
  test/CodeGenCXX/cxx11-initializer-aggregate.cpp
  test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
  test/SemaCXX/large-array-init.cpp

Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,40 @@
   return type;
 }
 
+/// Checks if the specified initializer is equivalent to zero initialization.
+static bool isZeroInitializer(ConstantEmitter &CE, const Expr *Init) {
+  if (auto *E = dyn_cast_or_null(Init)) {
+CXXConstructorDecl *CD = E->getConstructor();
+return CD->isDefaultConstructor() && CD->isTrivial();
+  }
+
+  if (auto *IL = dyn_cast_or_null(Init)) {
+for (auto I : IL->inits())
+  if (!isZeroInitializer(CE, I))
+return false;
+if (const Expr *Filler = IL->getArrayFiller())
+  return isZeroInitializer(CE, Filler);
+return true;
+  }
+
+  QualType InitTy = Init->getType();
+  if (InitTy->isIntegralOrEnumerationType() || InitTy->isPointerType()) {
+Expr::EvalResult Result;
+if (Init->EvaluateAsRValue(Result, CE.CGM.getContext()) &&
+!Result.hasUnacceptableSideEffect(Expr::SE_NoSideEffects))
+  return (Result.Val.isInt() && Result.Val.getInt().isNullValue()) ||
+ (Result.Val.isLValue() && Result.Val.isNullPointer());
+  }
+
+  return false;
+}
+
 llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
   // Make a quick check if variable can be default NULL initialized
   // and avoid going through rest of code which may do, for c++11,
   // initialization of memory to all NULLs.
-  if (!D.hasLocalStorage()) {
-QualType Ty = CGM.getContext().getBaseElementType(D.getType());
-if (Ty->isRecordType())
-  if (const CXXConstructExpr *E =
-  dyn_cast_or_null(D.getInit())) {
-const CXXConstructorDecl *CD = E->getConstructor();
-if (CD->isTrivial() && CD->isDefaultConstructor())
-  return CGM.EmitNullConstant(D.getType());
-  }
-  }
+  if (!D.hasLocalStorage() && isZeroInitializer(*this, D.getInit()))
+return CGM.EmitNullConstant(D.getType());
 
   QualType destType = D.getType();
 
Index: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -10312,20 +10312,14 @@
  HandleConversionToBool(Scratch.Val, Result);
 }
 
-static bool hasUnacceptableSideEffect(Expr::EvalStatus &Result,
-  Expr::SideEffectsKind SEK) {
-  return (SEK < Expr::SE_AllowSideEffects && Result.HasSideEffects) ||
- (SEK < Expr::SE_AllowUndefinedBehavior && Result.HasUndefinedBehavior);
-}
-
 bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
  SideEffectsKind AllowSideEffects) const {
   if (!getType()->isIntegralOrEnumerationType())
 return false;
 
   EvalResult ExprResult;
   if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() ||
-  hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
+  ExprResult.hasUnacceptableSideEffect(AllowSideEffects))
 return false;
 
   Result = ExprResult.Val.getInt();
@@ -10339,7 +10333,7 @@
 
   EvalResult ExprResult;
   if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() ||
-  hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
+  ExprResult.hasUnacceptableSideEffect(AllowSideEffects))
 return false;
 
   Result = ExprResult.Val.getFloat();
@@ -10417,7 +10411,7 @@
 bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
   EvalResult Result;
   return EvaluateAsRValue(Result, Ctx) &&
- !hasUnacceptableSideEffect(Result, SEK);
+ !Result.hasUnacceptableSideEffect(SEK);
 }
 
 APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
Index: include/clang/AST/Expr.h
===
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -537,6 +537,13 @@
   bool isConstantInitializer(ASTContext &Ctx, bool ForRef,
  const Expr **Culprit = nullptr) const;
 
+  enum SideEffectsKind {
+SE_NoSideEffects,  ///< Strictly evaluate the expression.
+SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not
+   ///< arbitrary unmodeled side effects.
+SE_AllowSideEffects///< Allow any un

[PATCH] D47166: use zeroinitializer for (trailing zero portion of) large array initializers more reliably

2018-05-22 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff accepted this revision.
sepavloff added a comment.
This revision is now accepted and ready to land.

Now I understand your idea about moving the logic to `tryEmitPrivateForMemory`. 
Indeed it is more general and consistent solution.
Thank you.




Comment at: lib/CodeGen/CGExprConstant.cpp:643
+  llvm::Constant *Filler) {
+  // Figre out how long the initial prefix of non-zero elements is.
+  unsigned NonzeroLength = ArrayBound;

s/Figre/Figure/ ?



Comment at: lib/CodeGen/CGExprConstant.cpp:903
 SmallVector Elts;
-Elts.reserve(std::max(NumInitableElts, NumElements));
+if (fillC && fillC->isNullValue())
+  Elts.reserve(NumInitableElts + 1);

The check for `fillC != nullptr` here is redundant, it was checked few lines 
above.



Comment at: test/CodeGenCXX/cxx11-initializer-aggregate.cpp:83
+  struct S1 data_7[1024 * 1024 * 512] = {{0}};
+
+  // This variable must be initialized elementwise.

Array definitions:
```
char data_8[1000 * 1000 * 1000] = {};
int (&&data_9)[1000 * 1000 * 1000] = {0};
```
also compile successfully with this patch and hang compiler without it.


Repository:
  rC Clang

https://reviews.llvm.org/D47166



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


[PATCH] D24933: Enable configuration files in clang

2017-10-02 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Here is a list of design solutions used in this implementation of config files.

**How config file is specified**

There are two ways to specify config file:

- To encode it into executable file name, such as `foo-clang`,
- To pass config file in command line arguments.

There were no objections to the variant `foo-clang`. It can be considered as a 
natural extension of the existing mechanism, in which invocation of `foo-clang` 
is equivalent to specifying target in command line: `clang --target=foo`. 
Config file allows to specify more than one option and its name is not confined 
to the registered targets.

As for specifying config file in command line, there are two variants:

- Use existing construct `@foo`.
- Use special command line option `--config foo`.

Each way has own advantages.

Construct `@file` allows to reuse existing command line syntax. Indeed, config 
file is a collection of command line arguments and `@file` is just a way to 
inserts such arguments from a file. Config file may include other files and it 
uses `@file` with the exception that `file` is resolved relative to the 
including file, not to current directory. Config file could be considered as an 
extension of existing mechanism provided by `@file`.

Using `@file` creates compatibility issues, because existing use of `@file` 
must not be broken. Obviously the file in `@file` may be treated as 
configuration only if it cannot be treated according to the existing semantics. 
Possible solution is to try loading `file` as configuration if it does not 
contain path separator and is not found in current directory.

The drawback of this syntax is that the meaning of `@foo` in the invocation 
`clang @foo abc.cpp` depends on the content of current directory. If it 
contains file `foo`, `@foo` is an expansion of response file, otherwise it 
specifies a config file. This behavior causes error if current directory 
accidentally contains a file with the same name as the specified config file.

Using dedicated option to apply config file makes the intention explicit. It 
also allow to use config files from arbitrary places. For instance, invocation 
`clang --config ./foo` allows to treat file `foo` in current directory as 
config file.

Although config file contains command line arguments as conventional response 
file, it differs from the latter:

- It resolves nested `@file` constructs differently, relative to including 
file, not current directory.
- File is searched for in predefined set of directories, not in the current 
only.
- Config file is more like a part of working environment. For instance, clang 
based SDK supplier could deliver a set config files as a part of their product. 
Response file in contrast is more close to transient build data, often 
generated by some tool.
- Warning about unused options are suppressed in config files.
- There was a proposal to extend syntax of config file to enable comments and 
using trailing backslash to split long lines, although these extensions are 
useful for response files as well.

So, maybe, loading config file deserves a special option. This way has 
advantages:

- it expresses intentions explicitly and reduce risk of accidental errors,
- it allows using absolute paths to specify config file.

**Where config files reside**

There may be several places where config files can be kept:

- Directory where clang executable resides. It is convenient for SDK developers 
as it simplifies packaging. User can use several instances of clang at the same 
time, they still may use their own set of config files without conflicts.
- System directory (for instance, /etc/llvm), that keeps config files for use 
by several users. Such case is interesting for OS distribution maintainers and 
SDK developers.
- User directory (for instance, ~/.llvm). A user can collect config file that 
tune compiler for their tasks in this directory and use them to select 
particular option set.
- Config file can be specified by path,  as in `clang --config ./foo`. This is 
convenient for developers to ensure that particular configuration is selected.

For the sake of flexibility it make sense to enable all these locations as they 
are useful in different scenarios. Location of user and system directories are 
specified at configuration, by default they are absent. If user directory is 
specified, it should have higher priority over other places for search so that 
user could correct system supplied option sets.

**Driver mode**

If config file is encoded in executable name, such as `foo-clang`, there is 
concern of using different driver modes. What config file should be searched 
for if compiler is called as `foo-cpp`, `foo-cl` etc? These tools support 
different set of options, so a flexible solution should provide possibility to 
specify different config files for different driver modes.

Clang implements flexible scheme of tool naming, in which a tool name has 
components:

  --[-][]

The part 

[PATCH] D24933: Enable configuration files in clang

2017-10-09 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 118315.
sepavloff added a comment.

Updated patch according to reviewer's notes


https://reviews.llvm.org/D24933

Files:
  docs/UsersManual.rst
  include/clang/Basic/DiagnosticDriverKinds.td
  include/clang/Config/config.h.cmake
  include/clang/Driver/Driver.h
  include/clang/Driver/Options.td
  lib/Driver/Driver.cpp
  test/Driver/Inputs/config-1.cfg
  test/Driver/Inputs/config-2.cfg
  test/Driver/Inputs/config-2a.cfg
  test/Driver/Inputs/config-3.cfg
  test/Driver/Inputs/config-4.cfg
  test/Driver/Inputs/config-5.cfg
  test/Driver/Inputs/config/config-4.cfg
  test/Driver/config-file-errs.c
  test/Driver/config-file.c
  test/Driver/config-file.cpp

Index: test/Driver/config-file.cpp
===
--- /dev/null
+++ test/Driver/config-file.cpp
@@ -0,0 +1,65 @@
+// REQUIRES: shell
+
+//--- Invocation qqq-clang-g++ tries to find config file qqq-clang-g++.cfg first ...
+//
+// RUN: mkdir -p %T/testdmode
+// RUN: [ ! -s %T/testdmode/qqq-clang-g++ ] || rm %T/testdmode/qqq-clang-g++
+// RUN: ln -s %clang %T/testdmode/qqq-clang-g++
+// RUN: echo "-Wundefined-func-template" > %T/testdmode/qqq-clang-g++.cfg
+// RUN: echo "-Werror" > %T/testdmode/qqq.cfg
+//
+// RUN: %T/testdmode/qqq-clang-g++ -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix FULL-NAME
+//
+// FULL-NAME: Configuration file: {{.*}}/testdmode/qqq-clang-g++.cfg
+// FULL-NAME: -Wundefined-func-template
+// FULL-NAME-NOT: -Werror
+//
+//--- ... and qqq.cfg if qqq-clang-g++.cfg is not found.
+//
+// RUN: rm %T/testdmode/qqq-clang-g++.cfg
+//
+// RUN: %T/testdmode/qqq-clang-g++ -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix SHORT-NAME
+//
+// SHORT-NAME: Configuration file: {{.*}}/testdmode/qqq.cfg
+// SHORT-NAME: -Werror
+// SHORT-NAME-NOT: -Wundefined-func-template
+
+
+//--- Config files are searched for in binary directory as well.
+//
+// RUN: [ ! -s %T/testbin/clang ] || rm %T/testbin/clang
+// RUN: ln -s %clang %T/testbin/clang
+// RUN: echo "-Werror" > %T/testbin/aaa.cfg
+//
+// RUN: %T/testbin/clang --config aaa.cfg -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-BIN
+//
+// CHECK-BIN: Configuration file: {{.*}}/testbin/aaa.cfg
+// CHECK-BIN: -Werror
+
+
+//--- If command line contains options that change triple (for instance, -m32), clang tries
+//reloading config file.
+
+//--- When reloading config file, target-clang-g++ tries to find config target32-clang-g++.cfg first ...
+//
+// RUN: mkdir -p %T/testreload
+// RUN: [ ! -s %T/testreload/x86_64-clang-g++ ] || rm %T/testreload/x86_64-clang-g++
+// RUN: ln -s %clang %T/testreload/x86_64-clang-g++
+// RUN: echo "-Wundefined-func-template" > %T/testreload/i386-clang-g++.cfg
+// RUN: echo "-Werror" > %T/testreload/i386.cfg
+//
+// RUN: %T/testreload/x86_64-clang-g++ -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD
+//
+// CHECK-RELOAD: Configuration file: {{.*}}/testreload/i386-clang-g++.cfg
+// CHECK-RELOAD: -Wundefined-func-template
+// CHECK-RELOAD-NOT: -Werror
+
+//--- and target32.cfg if target32-g++.cfg is not found.
+//
+// RUN: rm %T/testreload/i386-clang-g++.cfg
+//
+// RUN: %T/testreload/x86_64-clang-g++ -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD2
+//
+// CHECK-RELOAD2: Configuration file: {{.*}}/testreload/i386.cfg
+// CHECK-RELOAD2: -Werror
+// CHECK-RELOAD2-NOT: -Wundefined-func-template
Index: test/Driver/config-file.c
===
--- /dev/null
+++ test/Driver/config-file.c
@@ -0,0 +1,50 @@
+//--- Config file (full path) in output of -###
+//
+// RUN: %clang --config %S/Inputs/config-1.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-HHH
+// CHECK-HHH: Target: x86_64-apple-darwin
+// CHECK-HHH: Configuration file: {{.*}}Inputs{{.}}config-1.cfg
+// CHECK-HHH: -Werror
+// CHECK-HHH: -std=c99
+
+
+//--- Nested config files
+//
+// RUN: %clang --config %S/Inputs/config-2.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-HHH2
+// CHECK-HHH2: Target: x86_64-unknown-linux
+// CHECK-HHH2: Configuration file: {{.*}}Inputs{{.}}config-2.cfg
+// CHECK-HHH2: -Wundefined-func-template
+//
+
+// RUN: %clang --config %S/Inputs/config-2a.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-HHH2a
+// CHECK-HHH2a: Target: x86_64-unknown-linux
+// CHECK-HHH2a: Configuration file: {{.*}}Inputs{{.}}config-2a.cfg
+// CHECK-HHH2a: -isysroot
+// CHECK-HHH2a-SAME: /opt/data
+
+
+//--- If config file isspecified by relative path (workdir/cfg-s2), it is searched for by that path.
+//
+// RUN: mkdir -p %T/workdir
+// RUN: echo "@subdir/cfg-s2" > %T/workdir/cfg-1
+// RUN: mkdir -p %T/workdir/subdir
+// RUN: echo "-Wundefined-var-template" > %T/workdir/subdir/cfg-s2
+//
+// RUN: ( cd %T && %clang --config workdir/cfg-1 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-REL )
+//
+// CHECK-REL: Configuration fi

[PATCH] D24933: Enable configuration files in clang

2017-10-09 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked 28 inline comments as done.
sepavloff added a comment.

@hfinkel Thank you for explanations!


https://reviews.llvm.org/D24933



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


[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-19 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: rsmith, rjmccall, ikudrin.

With this change compiler generates alignment checks for wider range
of types. Previously such checks were generated only for the record types
with non-trivial default constructor. So the types like:

  struct alignas(32) S2 { int x; };
  typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;

did not get checks when allocated by 'new' expression.

This change also optimizes the checks generated for the arrays created
in 'new' expressions. Previously the check was generated for each
invocation of type constructor. Now the check is generated only once
for entire array.


Repository:
  rC Clang

https://reviews.llvm.org/D49589

Files:
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCXX/ubsan-new-checks.cpp

Index: test/CodeGenCXX/ubsan-new-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-new-checks.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -S -emit-llvm -fsanitize=alignment %s -o - | FileCheck %s
+
+struct alignas(32) S1 {
+  int x;
+  S1();
+};
+
+struct alignas(32) S2 {
+  int x;
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+S1 *func_01() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_01v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   call void @_ZN2S1C1Ev(
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S2;
+}
+
+S2 *func_03() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_03v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t;
+}
+
+float32x2_t *func_05() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_05v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t[20];
+}
Index: lib/CodeGen/CodeGenFunction.h
===
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -376,6 +376,25 @@
 ~SanitizerScope();
   };
 
+  /// True if sanitizer checks for current pointer value are generated.
+  bool PointerChecksAreEmitted = false;
+
+  /// RAII object to track generation of sanitizer pointer checks.
+  class PointerChecksRAII {
+CodeGenFunction *CGF;
+bool PrevValue;
+  public:
+PointerChecksRAII(CodeGenFunction *CGF)
+: CGF(CGF), PrevValue(CGF->PointerChecksAreEmitted) {
+  CGF->PointerChecksAreEmitted = true;
+}
+~PointerChecksRAII() {
+  if (!PrevValue)
+CGF->PointerChecksAreEmitted = false;
+}
+bool shouldEmitChecks() const { return !PrevValue; }
+  };
+
   /// In C++, whether we are code generating a thunk.  This controls whether we
   /// should emit cleanups.
   bool CurFuncIsThunk = false;
Index: lib/CodeGen/CGExprCXX.cpp
===
--- lib/CodeGen/CGExprCXX.cpp
+++ lib/CodeGen/CGExprCXX.cpp
@@ -1271,6 +1271,15 @@
Address NewPtr, llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie) {
   ApplyDebugLocation DL(CGF, E);
+
+  // Emit sanitizer checks for pointer value now, so that in the case of an
+  // array it was checked only once and not at each constructor call.
+  CodeGenFunction::PointerChecksRAII PC(&CGF);
+  if (PC.shouldEmitChecks())
+CGF.EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall,
+E->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+NewPtr.getPointer(), ElementType);
+
   if (E->isArray())
 CGF.EmitNewArrayInitializer(E, ElementType, ElementTy, NewPtr, NumElements,
 AllocSizeWithoutCookie);
Index: lib/CodeGen/CGClass.cpp
===
--- lib/CodeGen/CGClass.cpp
+++ lib/CodeGen/CGClass.cpp
@@ -2068,11 +2068,10 @@
  SourceLocation Loc) {
   const CXXRecordDecl *ClassDecl = D->getParent();
 
-  // C++11 [class.mfct.non-static]p2:
-  //   If a non-

[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-23 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

In https://reviews.llvm.org/D49589#1171279, @ikudrin wrote:

> Did you consider dividing the patch into two separate changes to solve the 
> two described issues independently?


The both tow issues have the same cause: the check is genereated too late. Now 
it is generated during contructor generation. For arrays it means that every 
array element gets its own check. For types like vectors with required 
alignment it means no check at all, because technically such type do not have a 
constructor. If the check is generated earlier, while processing 'new' 
expression, both the problems are solved. But in this case we need to inform 
`EmitCXXConstructorCall` that the checks are already generated, because this 
function may be called in cases other than 'new' expression.


Repository:
  rC Clang

https://reviews.llvm.org/D49589



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


[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-24 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 157102.
sepavloff added a comment.

Updated patch

- Modified check generation. Now for each 'new' expression compiler tries to

generate the checks. It solves problem of 'nested' new expressions, which
appear when 'new' is used in default arguments.

- Field and RAII class names are made more specific.
- Added new tests including that with inplace new operator.


Repository:
  rC Clang

https://reviews.llvm.org/D49589

Files:
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCXX/ubsan-new-checks.cpp

Index: test/CodeGenCXX/ubsan-new-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-new-checks.cpp
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -S -emit-llvm -fsanitize=alignment %s -o - | FileCheck %s
+
+struct alignas(32) S1 {
+  int x;
+  S1();
+};
+
+struct alignas(32) S2 {
+  int x;
+};
+
+struct alignas(32) S3 {
+  int x;
+  S3(int *p = new int[4]);
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+
+void *operator new (unsigned long, void *p) { return p; }
+void *operator new[] (unsigned long, void *p) { return p; }
+
+S1 *func_01() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_01v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   call void @_ZN2S1C1Ev(
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S2;
+}
+
+S2 *func_03() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_03v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t;
+}
+
+float32x2_t *func_05() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_05v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t[20];
+}
+
+S3 *func_07() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_07v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S3;
+}
+
+S3 *func_08() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_08v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S3[10];
+}
+
+
+S2 *func_10(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_10Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new(p) S2;
+}
+
+S2 *func_11(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_11Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new(p) S2[10];
+}
+
+float32x2_t *func_12() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_12v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t;
+}
+
+float32x2_t *func_13() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_13v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t[20];
+}
Index: lib/CodeGen/CodeGenFunction.h
===
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -458,6 +458,23 @@
 ~SanitizerScope();
   };
 
+  /// True if sanitizer checks for the pointer returned by 'new' are generated.
+  bool NewPointerChecksAreEmitted = false;
+
+  /// RAII object to track generation of sanitizer checks for result of 'new'.
+  class NewPointerChecksRAII {
+CodeGenFunction *CGF;
+bool PrevValue;
+  public:
+NewPointerChecksRAII(CodeGenFunction *CGF)
+: CGF(CGF), PrevValue(CGF->NewPointerChecksAreEmitted) {
+  CGF->NewPointerChecksAreEmitted = true;
+}
+~NewPointer

[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-24 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added inline comments.



Comment at: lib/CodeGen/CodeGenFunction.h:380
+  /// True if sanitizer checks for current pointer value are generated.
+  bool PointerChecksAreEmitted = false;
+

rjmccall wrote:
> I don't think this is a good way of doing this.  Using global state makes 
> this unnecessarily difficult to reason about and can have unintended effects. 
>  For example, you are unintentionally suppressing any checks that would be 
> done as part of e.g. evaluating default arguments to the default constructor.
> 
> You should pass a parameter down that says whether checks are necessary.  You 
> can also use that parameter to e.g. suppress checks when constructing local 
> variables and temporaries, although you may already have an alternative 
> mechanism for doing that.
Passing parameter that inctructs whether to generate checks or not hardly can 
be directly implemented. This information is used in `EmitCXXConstructorCall` 
and it is formed during processing of `new` expression. The distance between 
these points can be 10 call frames, in some of them (`StmtVisitor` interface of 
`AggExprEmitter`) we cannot change function parameters.
The case of `new` expression in default arguments indeed handled incorrectly, 
thank you for the catch.  The updated version must process this case correctly.


Repository:
  rC Clang

https://reviews.llvm.org/D49589



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


[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-25 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 157305.
sepavloff added a comment.

Updated patch

Now the information, if the pointer produced by 'new' operator is checked,
is stored in objects used for pointer representation (`Address` and
`AggValueSlot`) rather than globally.

Also the tests were cleaned up a bit.


Repository:
  rC Clang

https://reviews.llvm.org/D49589

Files:
  lib/CodeGen/Address.h
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CGValue.h
  test/CodeGenCXX/ubsan-new-checks.cpp

Index: test/CodeGenCXX/ubsan-new-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-new-checks.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -S -emit-llvm -fsanitize=alignment %s -o - | FileCheck %s
+
+struct alignas(32) S1 {
+  int x;
+  S1();
+};
+
+struct alignas(32) S2 {
+  int x;
+};
+
+struct alignas(32) S3 {
+  int x;
+  S3(int *p = new int[4]);
+};
+
+struct S4 : public S3 {
+  S4() : S3() {}
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+struct S5 {
+  float32x2_t x;
+};
+
+void *operator new (unsigned long, void *p) { return p; }
+void *operator new[] (unsigned long, void *p) { return p; }
+
+S1 *func_01() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_01v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   call void @_ZN2S1C1Ev(
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S1*
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new S2;
+}
+
+S2 *func_03() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_03v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S2*
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_05() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_05v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S3 *func_07() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_07v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3;
+}
+
+S3 *func_08() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_08v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3[10];
+}
+
+
+S2 *func_10(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_10Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2;
+}
+
+S2 *func_11(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_11Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2[10];
+}
+
+float32x2_t *func_12() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_12v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_13() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_13v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S4 *func_14() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_14v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S4*
+  return new S4;
+}
+
+S5 *func_15(const S5 *ptr) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_15PK2S5
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64
+  // CHECK:   ret %struct.S5*
+  return new S5(*ptr);
+}
Index: lib/CodeGen/CGValue.h
===

[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-26 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 157519.
sepavloff added a comment.

Updated patch

Now information, if sanitizer checks are generated while processing 'new'
expression, is passed through function call arguments.


Repository:
  rC Clang

https://reviews.llvm.org/D49589

Files:
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CGValue.h
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCXX/ubsan-new-checks.cpp

Index: test/CodeGenCXX/ubsan-new-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-new-checks.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -S -emit-llvm -fsanitize=alignment %s -o - | FileCheck %s
+
+struct alignas(32) S1 {
+  int x;
+  S1();
+};
+
+struct alignas(32) S2 {
+  int x;
+};
+
+struct alignas(32) S3 {
+  int x;
+  S3(int *p = new int[4]);
+};
+
+struct S4 : public S3 {
+  S4() : S3() {}
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+struct S5 {
+  float32x2_t x;
+};
+
+void *operator new (unsigned long, void *p) { return p; }
+void *operator new[] (unsigned long, void *p) { return p; }
+
+S1 *func_01() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_01v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   call void @_ZN2S1C1Ev(
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S1*
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new S2;
+}
+
+S2 *func_03() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_03v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S2*
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_05() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_05v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S3 *func_07() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_07v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3;
+}
+
+S3 *func_08() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_08v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3[10];
+}
+
+
+S2 *func_10(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_10Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2;
+}
+
+S2 *func_11(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_11Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2[10];
+}
+
+float32x2_t *func_12() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_12v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_13() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_13v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S4 *func_14() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_14v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S4*
+  return new S4;
+}
+
+S5 *func_15(const S5 *ptr) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_15PK2S5
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64
+  // CHECK:   ret %struct.S5*
+  return new S5(*ptr);
+}
Index: lib/CodeGen/CodeGenFunction.h
===
--- lib/CodeGen/Co

[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-26 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

> Also, please remember that your analysis is not the only thing happening in 
> the compiler.  isChecked is not a meaningful name taken out of context.

`Address` is not modified in the current patch version. As for `AggValueSlot`, 
this method name is leaved, as there is no other meaning for this class. Please 
let me know if it is inappropriate.


Repository:
  rC Clang

https://reviews.llvm.org/D49589



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


[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-26 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 157643.
sepavloff added a comment.

Updated patch

Added names for boolean arguments, renamed a field in AggValueSlot.
No functional changes.


Repository:
  rC Clang

https://reviews.llvm.org/D49589

Files:
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CGValue.h
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCXX/ubsan-new-checks.cpp

Index: test/CodeGenCXX/ubsan-new-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-new-checks.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -S -emit-llvm -fsanitize=alignment %s -o - | FileCheck %s
+
+struct alignas(32) S1 {
+  int x;
+  S1();
+};
+
+struct alignas(32) S2 {
+  int x;
+};
+
+struct alignas(32) S3 {
+  int x;
+  S3(int *p = new int[4]);
+};
+
+struct S4 : public S3 {
+  S4() : S3() {}
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+struct S5 {
+  float32x2_t x;
+};
+
+void *operator new (unsigned long, void *p) { return p; }
+void *operator new[] (unsigned long, void *p) { return p; }
+
+S1 *func_01() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_01v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   call void @_ZN2S1C1Ev(
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S1*
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new S2;
+}
+
+S2 *func_03() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_03v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S2*
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_05() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_05v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S3 *func_07() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_07v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3;
+}
+
+S3 *func_08() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_08v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3[10];
+}
+
+
+S2 *func_10(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_10Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2;
+}
+
+S2 *func_11(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_11Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2[10];
+}
+
+float32x2_t *func_12() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_12v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_13() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_13v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S4 *func_14() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_14v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S4*
+  return new S4;
+}
+
+S5 *func_15(const S5 *ptr) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_15PK2S5
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64
+  // CHECK:   ret %struct.S5*
+  return new S5(*ptr);
+}
Index: lib/CodeGen/CodeGenFunction.h
===
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGe

[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-27 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 157677.
sepavloff added a comment.

Updated patch

Use `SanitizerCheck` instead of `Check` in method and enum names.
No functional changes.


Repository:
  rC Clang

https://reviews.llvm.org/D49589

Files:
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CGValue.h
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCXX/ubsan-new-checks.cpp

Index: test/CodeGenCXX/ubsan-new-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-new-checks.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -S -emit-llvm -fsanitize=alignment %s -o - | FileCheck %s
+
+struct alignas(32) S1 {
+  int x;
+  S1();
+};
+
+struct alignas(32) S2 {
+  int x;
+};
+
+struct alignas(32) S3 {
+  int x;
+  S3(int *p = new int[4]);
+};
+
+struct S4 : public S3 {
+  S4() : S3() {}
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+struct S5 {
+  float32x2_t x;
+};
+
+void *operator new (unsigned long, void *p) { return p; }
+void *operator new[] (unsigned long, void *p) { return p; }
+
+S1 *func_01() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_01v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   call void @_ZN2S1C1Ev(
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S1*
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new S2;
+}
+
+S2 *func_03() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_03v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S2*
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_05() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_05v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S3 *func_07() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_07v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3;
+}
+
+S3 *func_08() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_08v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3[10];
+}
+
+
+S2 *func_10(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_10Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2;
+}
+
+S2 *func_11(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_11Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2[10];
+}
+
+float32x2_t *func_12() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_12v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_13() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_13v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S4 *func_14() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_14v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S4*
+  return new S4;
+}
+
+S5 *func_15(const S5 *ptr) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_15PK2S5
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64
+  // CHECK:   ret %struct.S5*
+  return new S5(*ptr);
+}
Index: lib/CodeGen/CodeGenFunction.h
===
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenF

[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-27 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

@rjmccall Thank you!


Repository:
  rC Clang

https://reviews.llvm.org/D49589



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


[PATCH] D49589: [UBSan] Strengthen pointer checks in 'new' expressions

2018-07-28 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL338199: [UBSan] Strengthen pointer checks in 'new' 
expressions (authored by sepavloff, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D49589

Files:
  cfe/trunk/lib/CodeGen/CGClass.cpp
  cfe/trunk/lib/CodeGen/CGExprCXX.cpp
  cfe/trunk/lib/CodeGen/CGValue.h
  cfe/trunk/lib/CodeGen/CodeGenFunction.h
  cfe/trunk/test/CodeGenCXX/ubsan-new-checks.cpp

Index: cfe/trunk/test/CodeGenCXX/ubsan-new-checks.cpp
===
--- cfe/trunk/test/CodeGenCXX/ubsan-new-checks.cpp
+++ cfe/trunk/test/CodeGenCXX/ubsan-new-checks.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -S -emit-llvm -fsanitize=alignment %s -o - | FileCheck %s
+
+struct alignas(32) S1 {
+  int x;
+  S1();
+};
+
+struct alignas(32) S2 {
+  int x;
+};
+
+struct alignas(32) S3 {
+  int x;
+  S3(int *p = new int[4]);
+};
+
+struct S4 : public S3 {
+  S4() : S3() {}
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+struct S5 {
+  float32x2_t x;
+};
+
+void *operator new (unsigned long, void *p) { return p; }
+void *operator new[] (unsigned long, void *p) { return p; }
+
+S1 *func_01() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_01v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   call void @_ZN2S1C1Ev(
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S1*
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new S2;
+}
+
+S2 *func_03() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_03v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S2*
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_05() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_05v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S3 *func_07() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_07v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3;
+}
+
+S3 *func_08() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_08v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S3*
+  return new S3[10];
+}
+
+
+S2 *func_10(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_10Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2;
+}
+
+S2 *func_11(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_11Pv
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret %struct.S2*
+  return new(p) S2[10];
+}
+
+float32x2_t *func_12() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_12v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t;
+}
+
+float32x2_t *func_13() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_13v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S4 *func_14() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_14v
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:   ret %struct.S4*
+  return new S4;
+}
+
+S5 *func_15(const S5 *ptr) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_15PK2S5
+  // CHECK:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64
+  // CHECK:   ret %struct.S5*
+  return new S5(*ptr);
+}

[PATCH] D43017: Clean up use of C allocation functions

2018-02-07 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: akyrtzi, rnk.

This change cleans up uses of malloc/calloc/realloc. In the case where
the return value is not checked agains null pointer, the call to
'std::malloc' is replaced by 'llvm::malloc', which reports fatal error
on allocation failure. In plain C files, assertion statements are added
to ensure that memory is successfully allocated.

The aim of this change is to get better diagnostics of OOM on Windows.


Repository:
  rC Clang

https://reviews.llvm.org/D43017

Files:
  include/clang/Sema/ParsedTemplate.h
  lib/AST/NestedNameSpecifier.cpp
  lib/Frontend/CacheTokens.cpp
  lib/Frontend/Rewrite/HTMLPrint.cpp
  lib/Lex/MacroArgs.cpp
  tools/c-index-test/c-index-test.c
  tools/libclang/BuildSystem.cpp
  tools/libclang/CIndex.cpp
  tools/libclang/CXString.cpp

Index: tools/libclang/CXString.cpp
===
--- tools/libclang/CXString.cpp
+++ tools/libclang/CXString.cpp
@@ -96,7 +96,7 @@
 
 CXString createDup(StringRef String) {
   CXString Result;
-  char *Spelling = static_cast(malloc(String.size() + 1));
+  char *Spelling = static_cast(llvm::malloc(String.size() + 1));
   memmove(Spelling, String.data(), String.size());
   Spelling[String.size()] = 0;
   Result.data = Spelling;
Index: tools/libclang/CIndex.cpp
===
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -,7 +,8 @@
   if (CXTokens.empty())
 return;
 
-  *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size());
+  *Tokens = static_cast(
+  llvm::malloc(sizeof(CXToken) * CXTokens.size()));
   memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size());
   *NumTokens = CXTokens.size();
 }
Index: tools/libclang/BuildSystem.cpp
===
--- tools/libclang/BuildSystem.cpp
+++ tools/libclang/BuildSystem.cpp
@@ -17,6 +17,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/Chrono.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -78,7 +79,7 @@
   unwrap(VFO)->write(OS);
 
   StringRef Data = OS.str();
-  *out_buffer_ptr = (char*)malloc(Data.size());
+  *out_buffer_ptr = static_cast(llvm::malloc(Data.size()));
   *out_buffer_size = Data.size();
   memcpy(*out_buffer_ptr, Data.data(), Data.size());
   return CXError_Success;
@@ -140,7 +141,7 @@
   OS << "}\n";
 
   StringRef Data = OS.str();
-  *out_buffer_ptr = (char*)malloc(Data.size());
+  *out_buffer_ptr = static_cast(llvm::malloc(Data.size()));
   *out_buffer_size = Data.size();
   memcpy(*out_buffer_ptr, Data.data(), Data.size());
   return CXError_Success;
Index: tools/c-index-test/c-index-test.c
===
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -232,6 +232,7 @@
   *unsaved_files
 = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
  *num_unsaved_files);
+  assert(unsaved_files);
   for (i = 0; i != *num_unsaved_files; ++i) {
 struct CXUnsavedFile *unsaved = *unsaved_files + i;
 const char *arg_string = argv[arg_indices[i]] + prefix_len;
@@ -267,6 +268,7 @@
 
 /* Read the contents of the file we're remapping to. */
 contents = (char *)malloc(unsaved->Length + 1);
+assert(contents);
 if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
   fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
   (feof(to_file) ? "EOF" : "error"), sep + 1);
@@ -286,6 +288,7 @@
 /* Copy the file name that we're remapping from. */
 filename_len = sep - arg_string;
 filename = (char *)malloc(filename_len + 1);
+assert(filename);
 memcpy(filename, arg_string, filename_len);
 filename[filename_len] = 0;
 unsaved->Filename = filename;
@@ -340,6 +343,7 @@
 = (struct CXUnsavedFile *)realloc(unsaved_files_no_try_idx,
   sizeof(struct CXUnsavedFile) *
 *num_unsaved_files);
+  assert(unsaved_files);
   memcpy(*unsaved_files + num_unsaved_files_no_try_idx,
  unsaved_files_try_idx, sizeof(struct CXUnsavedFile) *
 num_unsaved_files_try_idx);
@@ -2169,6 +2173,7 @@
 
   /* Copy the file name. */
   *filename = (char*)malloc(last_colon - input + 1);
+  assert(*filename);
   memcpy(*filename, input, last_colon - input);
   (*filename)[last_colon - input] = 0;
   return 0;
@@ -2578,6 +2583,7 @@
   assert(NumLocations > 0 && "Unable to count locations?");
   Locations = (CursorSourceLocation *)malloc(
   NumLocations * sizeof(CursorSourceLocation));
+  assert(Locations);
   for (Loc = 0; Loc < NumLocations; ++Loc) {
 const char *input = argv[Loc + 1] + strlen(loc

[PATCH] D36701: Use Token::isOneOf method in Parser.

2018-02-15 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff accepted this revision.
sepavloff added a comment.
This revision is now accepted and ready to land.

LGTM


https://reviews.llvm.org/D36701



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


[PATCH] D43017: Clean up use of C allocation functions

2018-02-20 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL325661: Clean up use of C allocation functions (authored by 
sepavloff, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D43017?vs=133201&id=135185#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D43017

Files:
  cfe/trunk/include/clang/Sema/ParsedTemplate.h
  cfe/trunk/lib/AST/NestedNameSpecifier.cpp
  cfe/trunk/lib/Frontend/CacheTokens.cpp
  cfe/trunk/lib/Frontend/Rewrite/HTMLPrint.cpp
  cfe/trunk/lib/Lex/MacroArgs.cpp
  cfe/trunk/tools/c-index-test/c-index-test.c
  cfe/trunk/tools/libclang/BuildSystem.cpp
  cfe/trunk/tools/libclang/CIndex.cpp
  cfe/trunk/tools/libclang/CXString.cpp

Index: cfe/trunk/include/clang/Sema/ParsedTemplate.h
===
--- cfe/trunk/include/clang/Sema/ParsedTemplate.h
+++ cfe/trunk/include/clang/Sema/ParsedTemplate.h
@@ -199,8 +199,7 @@
SourceLocation LAngleLoc, SourceLocation RAngleLoc,
ArrayRef TemplateArgs,
SmallVectorImpl &CleanupList) {
-
-  TemplateIdAnnotation *TemplateId = new (std::malloc(
+  TemplateIdAnnotation *TemplateId = new (llvm::safe_malloc(
   totalSizeToAlloc(TemplateArgs.size(
   TemplateIdAnnotation(SS, TemplateKWLoc, TemplateNameLoc, Name,
OperatorKind, OpaqueTemplateName, TemplateKind,
Index: cfe/trunk/lib/Frontend/Rewrite/HTMLPrint.cpp
===
--- cfe/trunk/lib/Frontend/Rewrite/HTMLPrint.cpp
+++ cfe/trunk/lib/Frontend/Rewrite/HTMLPrint.cpp
@@ -86,8 +86,7 @@
 
   // Emit the HTML.
   const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID);
-  char *Buffer = (char*)malloc(RewriteBuf.size());
-  std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer);
-  Out->write(Buffer, RewriteBuf.size());
-  free(Buffer);
+  std::unique_ptr Buffer(new char[RewriteBuf.size()]);
+  std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer.get());
+  Out->write(Buffer.get(), RewriteBuf.size());
 }
Index: cfe/trunk/lib/Frontend/CacheTokens.cpp
===
--- cfe/trunk/lib/Frontend/CacheTokens.cpp
+++ cfe/trunk/lib/Frontend/CacheTokens.cpp
@@ -662,7 +662,8 @@
   //  (2) a map from (IdentifierInfo*, Offset)* -> persistent IDs
 
   // Note that we use 'calloc', so all the bytes are 0.
-  PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey));
+  PTHIdKey *IIDMap = static_cast(
+  llvm::safe_calloc(idcount, sizeof(PTHIdKey)));
 
   // Create the hashtable.
   llvm::OnDiskChainedHashTableGenerator IIOffMap;
Index: cfe/trunk/lib/Lex/MacroArgs.cpp
===
--- cfe/trunk/lib/Lex/MacroArgs.cpp
+++ cfe/trunk/lib/Lex/MacroArgs.cpp
@@ -49,7 +49,8 @@
   if (!ResultEnt) {
 // Allocate memory for a MacroArgs object with the lexer tokens at the end,
 // and construct the MacroArgs object.
-Result = new (std::malloc(totalSizeToAlloc(UnexpArgTokens.size(
+Result = new (
+llvm::safe_malloc(totalSizeToAlloc(UnexpArgTokens.size(
 MacroArgs(UnexpArgTokens.size(), VarargsElided, MI->getNumParams());
   } else {
 Result = *ResultEnt;
Index: cfe/trunk/lib/AST/NestedNameSpecifier.cpp
===
--- cfe/trunk/lib/AST/NestedNameSpecifier.cpp
+++ cfe/trunk/lib/AST/NestedNameSpecifier.cpp
@@ -466,7 +466,7 @@
 unsigned NewCapacity = std::max(
 (unsigned)(BufferCapacity ? BufferCapacity * 2 : sizeof(void *) * 2),
 (unsigned)(BufferSize + (End - Start)));
-char *NewBuffer = static_cast(malloc(NewCapacity));
+char *NewBuffer = static_cast(llvm::safe_malloc(NewCapacity));
 if (BufferCapacity) {
   memcpy(NewBuffer, Buffer, BufferSize);
   free(Buffer);
Index: cfe/trunk/tools/libclang/BuildSystem.cpp
===
--- cfe/trunk/tools/libclang/BuildSystem.cpp
+++ cfe/trunk/tools/libclang/BuildSystem.cpp
@@ -17,6 +17,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/Chrono.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -78,7 +79,7 @@
   unwrap(VFO)->write(OS);
 
   StringRef Data = OS.str();
-  *out_buffer_ptr = (char*)malloc(Data.size());
+  *out_buffer_ptr = static_cast(llvm::safe_malloc(Data.size()));
   *out_buffer_size = Data.size();
   memcpy(*out_buffer_ptr, Data.data(), Data.size());
   return CXError_Success;
@@ -140,7 +141,7 @@
   OS << "}\n";
 
   StringRef Data = OS.str();
-  *out_buffer_ptr = (char*)malloc(Data.size());
+  *out_buffer_ptr = static_cast(llvm::safe_malloc(Data.size()));
   *out_buffer_size = Data.size();
   memcpy(*out_buffer_ptr, Data.data(), Data.size());
   return CXError

[PATCH] D33173: Modify test to look for patterns in stderr as well

2017-05-24 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL303735: Modify test so that it looks for patterns in stderr 
as well (authored by sepavloff).

Changed prior to commit:
  https://reviews.llvm.org/D33173?vs=98928&id=100062#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D33173

Files:
  clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp


Index: clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp
@@ -1,11 +1,11 @@
 // RUN: clang-tidy -checks='-*,modernize-use-override' %s.nonexistent.cpp -- | 
FileCheck -check-prefix=CHECK1 -implicit-check-not='{{warning:|error:}}' %s
-// RUN: clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' 
%s -- -fan-unknown-option | FileCheck -check-prefix=CHECK2 
-implicit-check-not='{{warning:|error:}}' %s
-// RUN: clang-tidy 
-checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %s 
-- -fan-unknown-option | FileCheck -check-prefix=CHECK3 
-implicit-check-not='{{warning:|error:}}' %s
+// RUN: clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' 
%s -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK2 
-implicit-check-not='{{warning:|error:}}' %s
+// RUN: clang-tidy 
-checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %s 
-- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK3 
-implicit-check-not='{{warning:|error:}}' %s
 // RUN: clang-tidy 
-checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %s -- 
-DMACRO_FROM_COMMAND_LINE | FileCheck -check-prefix=CHECK4 
-implicit-check-not='{{warning:|error:}}' %s
 
 // CHECK1: error: error reading '{{.*}}.nonexistent.cpp' 
[clang-diagnostic-error]
-// CHECK2: error: unknown argument: '-fan-unknown-option' 
[clang-diagnostic-error]
-// CHECK3: error: unknown argument: '-fan-unknown-option' 
[clang-diagnostic-error]
+// CHECK2: error: unknown argument: '-fan-unknown-option'
+// CHECK3: error: unknown argument: '-fan-unknown-option'
 
 // CHECK2: :[[@LINE+2]]:9: warning: implicit conversion from 'double' to 'int' 
changes value from 1.5 to 1 [clang-diagnostic-literal-conversion]
 // CHECK3: :[[@LINE+1]]:9: warning: implicit conversion from 'double' to 'int' 
changes value


Index: clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp
@@ -1,11 +1,11 @@
 // RUN: clang-tidy -checks='-*,modernize-use-override' %s.nonexistent.cpp -- | FileCheck -check-prefix=CHECK1 -implicit-check-not='{{warning:|error:}}' %s
-// RUN: clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %s -- -fan-unknown-option | FileCheck -check-prefix=CHECK2 -implicit-check-not='{{warning:|error:}}' %s
-// RUN: clang-tidy -checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %s -- -fan-unknown-option | FileCheck -check-prefix=CHECK3 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %s -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK2 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %s -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK3 -implicit-check-not='{{warning:|error:}}' %s
 // RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %s -- -DMACRO_FROM_COMMAND_LINE | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s
 
 // CHECK1: error: error reading '{{.*}}.nonexistent.cpp' [clang-diagnostic-error]
-// CHECK2: error: unknown argument: '-fan-unknown-option' [clang-diagnostic-error]
-// CHECK3: error: unknown argument: '-fan-unknown-option' [clang-diagnostic-error]
+// CHECK2: error: unknown argument: '-fan-unknown-option'
+// CHECK3: error: unknown argument: '-fan-unknown-option'
 
 // CHECK2: :[[@LINE+2]]:9: warning: implicit conversion from 'double' to 'int' changes value from 1.5 to 1 [clang-diagnostic-literal-conversion]
 // CHECK3: :[[@LINE+1]]:9: warning: implicit conversion from 'double' to 'int' changes value
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33272: Method loadFromCommandLine should be able to report errors

2017-05-24 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL303741: Method loadFromCommandLine should be able to report 
errors (authored by sepavloff).

Changed prior to commit:
  https://reviews.llvm.org/D33272?vs=99919&id=100069#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D33272

Files:
  cfe/trunk/include/clang/Tooling/CompilationDatabase.h
  cfe/trunk/lib/Frontend/CreateInvocationFromCommandLine.cpp
  cfe/trunk/lib/Tooling/CommonOptionsParser.cpp
  cfe/trunk/lib/Tooling/CompilationDatabase.cpp
  cfe/trunk/lib/Tooling/Tooling.cpp
  cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp

Index: cfe/trunk/include/clang/Tooling/CompilationDatabase.h
===
--- cfe/trunk/include/clang/Tooling/CompilationDatabase.h
+++ cfe/trunk/include/clang/Tooling/CompilationDatabase.h
@@ -176,10 +176,11 @@
   /// the number of arguments before "--", if "--" was found in the argument
   /// list.
   /// \param Argv Points to the command line arguments.
+  /// \param ErrorMsg Contains error text if the function returns null pointer.
   /// \param Directory The base directory used in the FixedCompilationDatabase.
-  static FixedCompilationDatabase *loadFromCommandLine(int &Argc,
-   const char *const *Argv,
-   Twine Directory = ".");
+  static std::unique_ptr loadFromCommandLine(
+  int &Argc, const char *const *Argv, std::string &ErrorMsg,
+  Twine Directory = ".");
 
   /// \brief Constructs a compilation data base from a specified directory
   /// and command line.
Index: cfe/trunk/lib/Frontend/CreateInvocationFromCommandLine.cpp
===
--- cfe/trunk/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ cfe/trunk/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -52,6 +52,8 @@
   TheDriver.setCheckInputsExist(false);
 
   std::unique_ptr C(TheDriver.BuildCompilation(Args));
+  if (!C)
+return nullptr;
 
   // Just print the cc1 options if -### was present.
   if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
Index: cfe/trunk/lib/Tooling/Tooling.cpp
===
--- cfe/trunk/lib/Tooling/Tooling.cpp
+++ cfe/trunk/lib/Tooling/Tooling.cpp
@@ -260,6 +260,8 @@
   Driver->setCheckInputsExist(false);
   const std::unique_ptr Compilation(
   Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
+  if (!Compilation)
+return false;
   const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
   &Diagnostics, Compilation.get());
   if (!CC1Args) {
Index: cfe/trunk/lib/Tooling/CompilationDatabase.cpp
===
--- cfe/trunk/lib/Tooling/CompilationDatabase.cpp
+++ cfe/trunk/lib/Tooling/CompilationDatabase.cpp
@@ -27,6 +27,7 @@
 #include "llvm/Option/Arg.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
 #include 
 #include 
 using namespace clang;
@@ -150,23 +151,21 @@
 // options.
 class UnusedInputDiagConsumer : public DiagnosticConsumer {
 public:
-  UnusedInputDiagConsumer() : Other(nullptr) {}
-
-  // Useful for debugging, chain diagnostics to another consumer after
-  // recording for our own purposes.
-  UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {}
+  UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
 
   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
 const Diagnostic &Info) override {
 if (Info.getID() == clang::diag::warn_drv_input_file_unused) {
   // Arg 1 for this diagnostic is the option that didn't get used.
   UnusedInputs.push_back(Info.getArgStdStr(0));
+} else if (DiagLevel >= DiagnosticsEngine::Error) {
+  // If driver failed to create compilation object, show the diagnostics
+  // to user.
+  Other.HandleDiagnostic(DiagLevel, Info);
 }
-if (Other)
-  Other->HandleDiagnostic(DiagLevel, Info);
   }
 
-  DiagnosticConsumer *Other;
+  DiagnosticConsumer &Other;
   SmallVector UnusedInputs;
 };
 
@@ -205,9 +204,12 @@
 ///  \li false if \c Args cannot be used for compilation jobs (e.g.
 ///  contains an option like -E or -version).
 static bool stripPositionalArgs(std::vector Args,
-std::vector &Result) {
+std::vector &Result,
+std::string &ErrorMsg) {
   IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions();
-  UnusedInputDiagConsumer DiagClient;
+  llvm::raw_string_ostream Output(ErrorMsg);
+  TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
+  UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
   DiagnosticsEngine Diagnostics(
   IntrusiveRefCntPtr(new DiagnosticIDs()),
   &*DiagOpts, &Diag

[PATCH] D33013: Driver must return non-zero code on errors in command line

2017-05-24 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL303756: Driver must return non-zero code on errors in 
command line (authored by sepavloff).

Changed prior to commit:
  https://reviews.llvm.org/D33013?vs=99273&id=100090#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D33013

Files:
  cfe/trunk/lib/Driver/Driver.cpp
  cfe/trunk/test/Driver/aarch64-cpus.c
  cfe/trunk/test/Driver/amdgpu-features.c
  cfe/trunk/test/Driver/arm-darwin-builtin.c
  cfe/trunk/test/Driver/arm-default-build-attributes.s
  cfe/trunk/test/Driver/cl-outputs.c
  cfe/trunk/test/Driver/clang_f_opts.c
  cfe/trunk/test/Driver/cuda-external-tools.cu
  cfe/trunk/test/Driver/debug-options.c
  cfe/trunk/test/Driver/gfortran.f90
  cfe/trunk/test/Driver/split-debug.h
  cfe/trunk/test/Driver/unknown-arg.c
  cfe/trunk/test/Index/index-attrs.c
  cfe/trunk/test/Index/index-attrs.cpp
  cfe/trunk/tools/driver/driver.cpp
  cfe/trunk/unittests/Driver/ToolChainTest.cpp

Index: cfe/trunk/lib/Driver/Driver.cpp
===
--- cfe/trunk/lib/Driver/Driver.cpp
+++ cfe/trunk/lib/Driver/Driver.cpp
@@ -598,6 +598,8 @@
   bool CCCPrintPhases;
 
   InputArgList Args = ParseArgStrings(ArgList.slice(1));
+  if (Diags.hasErrorOccurred())
+return nullptr;
 
   // Silence driver warnings if requested
   Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
Index: cfe/trunk/unittests/Driver/ToolChainTest.cpp
===
--- cfe/trunk/unittests/Driver/ToolChainTest.cpp
+++ cfe/trunk/unittests/Driver/ToolChainTest.cpp
@@ -60,6 +60,7 @@
 
   std::unique_ptr C(TheDriver.BuildCompilation(
   {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
+  EXPECT_TRUE(C);
 
   std::string S;
   {
@@ -99,6 +100,7 @@
 
   std::unique_ptr C(TheDriver.BuildCompilation(
   {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
+  EXPECT_TRUE(C);
 
   std::string S;
   {
@@ -128,15 +130,24 @@
 
   Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
   InMemoryFileSystem);
+  CCDriver.setCheckInputsExist(false);
   Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
InMemoryFileSystem);
+  CXXDriver.setCheckInputsExist(false);
   Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
   InMemoryFileSystem);
+  CLDriver.setCheckInputsExist(false);
 
-  std::unique_ptr CC(CCDriver.BuildCompilation({"foo.cpp"}));
-  std::unique_ptr CXX(CXXDriver.BuildCompilation({"foo.cpp"}));
-  std::unique_ptr CL(CLDriver.BuildCompilation({"foo.cpp"}));
-
+  std::unique_ptr CC(CCDriver.BuildCompilation(
+  { "/home/test/bin/clang", "foo.cpp"}));
+  std::unique_ptr CXX(CXXDriver.BuildCompilation(
+  { "/home/test/bin/clang++", "foo.cpp"}));
+  std::unique_ptr CL(CLDriver.BuildCompilation(
+  { "/home/test/bin/clang-cl", "foo.cpp"}));
+
+  EXPECT_TRUE(CC);
+  EXPECT_TRUE(CXX);
+  EXPECT_TRUE(CL);
   EXPECT_TRUE(CCDriver.CCCIsCC());
   EXPECT_TRUE(CXXDriver.CCCIsCXX());
   EXPECT_TRUE(CLDriver.IsCLMode());
Index: cfe/trunk/tools/driver/driver.cpp
===
--- cfe/trunk/tools/driver/driver.cpp
+++ cfe/trunk/tools/driver/driver.cpp
@@ -454,40 +454,41 @@
   SetBackdoorDriverOutputsFromEnvVars(TheDriver);
 
   std::unique_ptr C(TheDriver.BuildCompilation(argv));
-  int Res = 0;
-  SmallVector, 4> FailingCommands;
-  if (C.get())
+  int Res = 1;
+  if (C.get()) {
+SmallVector, 4> FailingCommands;
 Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
 
-  // Force a crash to test the diagnostics.
-  if (TheDriver.GenReproducer) {
-Diags.Report(diag::err_drv_force_crash)
+// Force a crash to test the diagnostics.
+if (TheDriver.GenReproducer) {
+  Diags.Report(diag::err_drv_force_crash)
 << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
 
-// Pretend that every command failed.
-FailingCommands.clear();
-for (const auto &J : C->getJobs())
-  if (const Command *C = dyn_cast(&J))
-FailingCommands.push_back(std::make_pair(-1, C));
-  }
-
-  for (const auto &P : FailingCommands) {
-int CommandRes = P.first;
-const Command *FailingCommand = P.second;
-if (!Res)
-  Res = CommandRes;
-
-// If result status is < 0, then the driver command signalled an error.
-// If result status is 70, then the driver command reported a fatal error.
-// On Windows, abort will return an exit code of 3.  In these cases,
-// generate additional diagnostic information if possible.
-bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
+  // Pretend that every command failed.
+  FailingCommands.clear();
+  for (const auto &J : C->getJobs())
+if (const Command *C = dyn_cast(&J))
+  FailingCommands.push_back(std::make_pair(-1, C));
+}
+
+for (const auto &P : FailingCommands) {
+ 

[PATCH] D30170: Function definition may have uninstantiated body

2017-05-27 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked 2 inline comments as done.
sepavloff added a comment.

In https://reviews.llvm.org/D30170#761342, @rsmith wrote:

> Do we really need two different notions of "definition" and "odr definition" 
> here? What goes wrong if we always treat the "instantiation of a friend 
> function definition" case as being a definition?


It requires 3 additional changes besides update of `isDefined`. All of them 
implement current behavior of the function and look like:

  @@ -3749,7 +3750,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation 
PointOfInstantiation,
bool Recursive,
bool DefinitionRequired,
bool AtEndOfTU) {
  -  if (Function->isInvalidDecl() || Function->isDefined())
  +  const FunctionDecl *Def;
  +  if (Function->isInvalidDecl() || (Function->isDefined(Def) && 
Def->isThisDeclarationADefinition()))
   return;
  
 // Never instantiate an explicit specialization except if it is a class 
scope

It make sense to replace this weird expression `Function->isDefined(Def) && 
Def->isThisDeclarationADefinition()` with a call to a new function, something 
like `isActuallyDefined`. So we anyway have to add a new function for checking 
function definition. In the case of `IsOdrDefinition` the new function is used 
in one place only, modified version of `isDefined` requires changes in 
unrelated code places.

Use of a special variant of `isDefined` dedicated to redefinition checks looks 
less invasive and more robust. If however there are reasons to use modified 
`isDefined`, it also can be implemented, there is nothing wrong with such 
solution.




Comment at: include/clang/AST/Decl.h:1829-1830
 
+  /// Returns true if the function is defined and other definitions are not
+  /// allowed in the redeclaration chain.
+  ///

rsmith wrote:
> This will not be true in the presence of modules: we will ensure that at most 
> one declaration has a body, but multiple declarations can be instantiated 
> from a defined member function of a class template, for instance. So I think 
> the constraint is that you're not allowed to add *more* such definitions.
Fixed also some comments according to this note.



Comment at: include/clang/AST/Decl.h:1848
+  return true;
+if (FunctionDecl *Original = getInstantiatedFromMemberFunction())
+  return Original->isOdrDefined();

rsmith wrote:
> I think this will do the wrong thing for an explicit specialization of a 
> member of a class template:
> 
> ```
> template struct A { void f() {}; };
> template<> void A::f();
> ```
> 
> Here, `A::f()` is "instantiated from a member function" but it's not a 
> definition, not even in the ODR sense. I think it would suffice to also check 
> whether `Original` is a friend declaration here.
Although this function is not called in this case, its name must agree with its 
functionality, so changed implementation as you recommend.



Comment at: lib/AST/Decl.cpp:2538
+if (I->isThisDeclarationADefinition()) {
+  Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
+  return true;

rsmith wrote:
> It seems incorrect to me for `isThisDeclarationADefinition()` to return 
> `true` on a redeclaration of a deleted function: only the first declaration 
> should be considered to be a definition in that case. (This special case 
> should be in `isThisDeclarationADefinition()`, not in `isDefined()`.)
Indeed, if a declaration was selected to be a definition, it is strange if 
`isThisDeclarationADefinition` returns false for it.



Comment at: lib/Sema/SemaDecl.cpp:11882
+
+  if (FD == Definition)
+return;

rsmith wrote:
> This looks wrong to me: `CheckForFunctionRedefinition` is intended to be 
> called *before* marking the function in question as a definition. If you call 
> it afterwards, then the `isOdrDefined` call won't work properly because it 
> will always check to see whether `FD` is a definition before checking any 
> other declaration. So any case that reaches here with `FD` being a definition 
> seems like a bug. I expect we're only getting here in that case due to the 
> missing check for friend in `isThisDeclarationAnOdrDefinition`.
`CheckForFunctionRedefinition` is called after the declaration is put to 
redeclaration chain. At this point the declaration does not have a body, so 
problem may arise only if the provided declaration is an instantiation. It 
happens when the method is called from `PerformPendingInstantiations` -> 
`InstantiateFunctionDefinition` -> `ActOnStartOfFunctionDef` -> 
`CheckForFunctionRedefinition`. In this case function body is generated for 
declaration that is already in redeclaration chain. If the chain is in valid 
state, it does not have duplicate definitions and call to 
`CheckForFunctionRedefinition` is redun

[PATCH] D30170: Function definition may have uninstantiated body

2017-05-27 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 100534.
sepavloff added a comment.

Updated patch

- Reduce number of added functions,
- Fixed some comments,
- Function `isOdrDefined` now checks uninstantiated bodies only for friend 
functions.


https://reviews.llvm.org/D30170

Files:
  include/clang/AST/Decl.h
  lib/AST/Decl.cpp
  lib/Sema/SemaDecl.cpp
  test/SemaCXX/cxx0x-cursory-default-delete.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -101,6 +101,34 @@
   friend void func_12(int x = 0);  // expected-error{{friend declaration specifying a default argument must be the only declaration}}
 };
 
+// Friend function with uninstantiated body is still a definition.
+
+template struct C20 {
+  friend void func_20() {} // expected-note{{previous definition is here}}
+};
+C20 c20i;
+void func_20() {} // expected-error{{redefinition of 'func_20'}}
+
+template struct C21a {
+  friend void func_21() {} // expected-note{{previous definition is here}}
+};
+template struct C21b {
+  friend void func_21() {} // expected-error{{redefinition of 'func_21'}}
+};
+C21a c21ai;
+C21b c21bi; // expected-note{{in instantiation of template class 'C21b' requested here}}
+
+template struct C22a {
+  friend void func_22() {} // expected-note{{previous definition is here}}
+};
+template struct C22b {
+  friend void func_22();
+};
+C22a c22ai;
+C22b c22bi;
+void func_22() {} // expected-error{{redefinition of 'func_22'}}
+
+
 
 namespace pr22307 {
 
Index: test/SemaCXX/cxx0x-cursory-default-delete.cpp
===
--- test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -136,13 +136,13 @@
 };
 
 struct DefaultDelete {
-  DefaultDelete() = default; // expected-note {{previous declaration is here}}
+  DefaultDelete() = default; // expected-note {{previous definition is here}}
   DefaultDelete() = delete; // expected-error {{constructor cannot be redeclared}}
 
-  ~DefaultDelete() = default; // expected-note {{previous declaration is here}}
+  ~DefaultDelete() = default; // expected-note {{previous definition is here}}
   ~DefaultDelete() = delete; // expected-error {{destructor cannot be redeclared}}
 
-  DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous declaration is here}}
+  DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous definition is here}}
   DefaultDelete &operator=(const DefaultDelete &) = delete; // expected-error {{class member cannot be redeclared}}
 };
 
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11875,8 +11875,12 @@
SkipBodyInfo *SkipBody) {
   const FunctionDecl *Definition = EffectiveDefinition;
   if (!Definition)
-if (!FD->isDefined(Definition))
+if (!FD->isOdrDefined(Definition))
   return;
+  assert(Definition);
+
+  if (FD == Definition)
+return;
 
   if (canRedefineFunction(Definition, getLangOpts()))
 return;
Index: lib/AST/Decl.cpp
===
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -2534,16 +2534,45 @@
 
 bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
   for (auto I : redecls()) {
-if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
-I->hasDefiningAttr()) {
+if (I->isThisDeclarationADefinition()) {
   Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
   return true;
 }
   }
 
   return false;
 }
 
+bool FunctionDecl::isOdrDefined(const FunctionDecl *&Definition) const {
+  // First try to find a declaration that has existing definition.
+  if (isDefined(Definition))
+return true;
+
+  // If no existing definition exist, look for a definition which can be
+  // instantiated.
+  for (auto I : redecls()) {
+if (I->getFriendObjectKind() != Decl::FOK_None) {
+  // If this is a friend function defined in a class template, it does not
+  // have a body until it is used, nevertheless it is a definition. The
+  // following code must produce redeclaration error:
+  //
+  // template struct C20 { friend void func_20() {} };
+  // C20 c20i;
+  // void func_20() {}
+  //
+  if (FunctionDecl *Original = I->getInstantiatedFromMemberFunction()) {
+const FunctionDecl *D;
+if (Original->isOdrDefined(D)) {
+  Definition = I;
+  return true;
+}
+  }
+}
+  }
+
+  return false;
+}
+
 Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
   if (!hasBody(Definition))
 return nullptr;
Index: include/clang/AST/Decl.h
===
--- include/clang

[PATCH] D33732: Catch invalid bitwise operation on vector of floats

2017-05-31 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.

Bitwise complement applied to vector of floats described with
attribute `ext_vector_type` is not diagnosed as error. Attempt to
compile such construct causes assertion violation in Instruction.cpp.
With this change the complement is treated similar to the case of
vector type described with attribute `vector_size`.


https://reviews.llvm.org/D33732

Files:
  lib/Sema/SemaExpr.cpp
  test/Sema/types.c


Index: test/Sema/types.c
===
--- test/Sema/types.c
+++ test/Sema/types.c
@@ -88,3 +88,8 @@
 int &*_Atomic null_type_0; // expected-error {{expected identifier or '('}}
 int &*__restrict__ null_type_1; // expected-error {{expected identifier or 
'('}}
 int ^_Atomic null_type_2; // expected-error {{block pointer to non-function 
type is invalid}}
+
+typedef float __attribute__((ext_vector_type(4)))  float4;
+float4 test3(float4 x) {
+  return ~x; // expected-error{{invalid argument type 'float4' (vector of 4 
'float' values) to unary expression}}
+}
Index: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11951,16 +11951,13 @@
   << resultType << Input.get()->getSourceRange();
 else if (resultType->hasIntegerRepresentation())
   break;
-else if (resultType->isExtVectorType()) {
-  if (Context.getLangOpts().OpenCL) {
-// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
-// on vector float types.
-QualType T = resultType->getAs()->getElementType();
-if (!T->isIntegerType())
-  return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-   << resultType << Input.get()->getSourceRange());
-  }
-  break;
+else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
+  // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+  // on vector float types.
+  QualType T = resultType->getAs()->getElementType();
+  if (!T->isIntegerType())
+return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+  << resultType << Input.get()->getSourceRange());
 } else {
   return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());


Index: test/Sema/types.c
===
--- test/Sema/types.c
+++ test/Sema/types.c
@@ -88,3 +88,8 @@
 int &*_Atomic null_type_0; // expected-error {{expected identifier or '('}}
 int &*__restrict__ null_type_1; // expected-error {{expected identifier or '('}}
 int ^_Atomic null_type_2; // expected-error {{block pointer to non-function type is invalid}}
+
+typedef float __attribute__((ext_vector_type(4)))  float4;
+float4 test3(float4 x) {
+  return ~x; // expected-error{{invalid argument type 'float4' (vector of 4 'float' values) to unary expression}}
+}
Index: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11951,16 +11951,13 @@
   << resultType << Input.get()->getSourceRange();
 else if (resultType->hasIntegerRepresentation())
   break;
-else if (resultType->isExtVectorType()) {
-  if (Context.getLangOpts().OpenCL) {
-// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
-// on vector float types.
-QualType T = resultType->getAs()->getElementType();
-if (!T->isIntegerType())
-  return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-   << resultType << Input.get()->getSourceRange());
-  }
-  break;
+else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
+  // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+  // on vector float types.
+  QualType T = resultType->getAs()->getElementType();
+  if (!T->isIntegerType())
+return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+  << resultType << Input.get()->getSourceRange());
 } else {
   return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D30170: Function definition may have uninstantiated body

2017-06-02 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 101260.
sepavloff added a comment.

Do not call getCanonicalDecl for deleted functions


https://reviews.llvm.org/D30170

Files:
  include/clang/AST/Decl.h
  lib/AST/Decl.cpp
  lib/Sema/SemaDecl.cpp
  test/SemaCXX/cxx0x-cursory-default-delete.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -101,6 +101,34 @@
   friend void func_12(int x = 0);  // expected-error{{friend declaration specifying a default argument must be the only declaration}}
 };
 
+// Friend function with uninstantiated body is still a definition.
+
+template struct C20 {
+  friend void func_20() {} // expected-note{{previous definition is here}}
+};
+C20 c20i;
+void func_20() {} // expected-error{{redefinition of 'func_20'}}
+
+template struct C21a {
+  friend void func_21() {} // expected-note{{previous definition is here}}
+};
+template struct C21b {
+  friend void func_21() {} // expected-error{{redefinition of 'func_21'}}
+};
+C21a c21ai;
+C21b c21bi; // expected-note{{in instantiation of template class 'C21b' requested here}}
+
+template struct C22a {
+  friend void func_22() {} // expected-note{{previous definition is here}}
+};
+template struct C22b {
+  friend void func_22();
+};
+C22a c22ai;
+C22b c22bi;
+void func_22() {} // expected-error{{redefinition of 'func_22'}}
+
+
 
 namespace pr22307 {
 
Index: test/SemaCXX/cxx0x-cursory-default-delete.cpp
===
--- test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -136,13 +136,13 @@
 };
 
 struct DefaultDelete {
-  DefaultDelete() = default; // expected-note {{previous declaration is here}}
+  DefaultDelete() = default; // expected-note {{previous definition is here}}
   DefaultDelete() = delete; // expected-error {{constructor cannot be redeclared}}
 
-  ~DefaultDelete() = default; // expected-note {{previous declaration is here}}
+  ~DefaultDelete() = default; // expected-note {{previous definition is here}}
   ~DefaultDelete() = delete; // expected-error {{destructor cannot be redeclared}}
 
-  DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous declaration is here}}
+  DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous definition is here}}
   DefaultDelete &operator=(const DefaultDelete &) = delete; // expected-error {{class member cannot be redeclared}}
 };
 
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11875,8 +11875,12 @@
SkipBodyInfo *SkipBody) {
   const FunctionDecl *Definition = EffectiveDefinition;
   if (!Definition)
-if (!FD->isDefined(Definition))
+if (!FD->isOdrDefined(Definition))
   return;
+  assert(Definition);
+
+  if (FD == Definition)
+return;
 
   if (canRedefineFunction(Definition, getLangOpts()))
 return;
Index: lib/AST/Decl.cpp
===
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -2534,16 +2534,45 @@
 
 bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
   for (auto I : redecls()) {
-if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
-I->hasDefiningAttr()) {
-  Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
+if (I->isThisDeclarationADefinition()) {
+  Definition = I;
   return true;
 }
   }
 
   return false;
 }
 
+bool FunctionDecl::isOdrDefined(const FunctionDecl *&Definition) const {
+  // First try to find a declaration that has existing definition.
+  if (isDefined(Definition))
+return true;
+
+  // If no existing definition exist, look for a definition which can be
+  // instantiated.
+  for (auto I : redecls()) {
+if (I->getFriendObjectKind() != Decl::FOK_None) {
+  // If this is a friend function defined in a class template, it does not
+  // have a body until it is used, nevertheless it is a definition. The
+  // following code must produce redeclaration error:
+  //
+  // template struct C20 { friend void func_20() {} };
+  // C20 c20i;
+  // void func_20() {}
+  //
+  if (FunctionDecl *Original = I->getInstantiatedFromMemberFunction()) {
+const FunctionDecl *D;
+if (Original->isOdrDefined(D)) {
+  Definition = I;
+  return true;
+}
+  }
+}
+  }
+
+  return false;
+}
+
 Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
   if (!hasBody(Definition))
 return nullptr;
Index: include/clang/AST/Decl.h
===
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1778,11 +1778,26 @@
 
   SourceRange getSo

[PATCH] D33732: Catch invalid bitwise operation on vector of floats

2017-06-04 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added inline comments.



Comment at: test/Sema/types.c:92
+
+typedef float __attribute__((ext_vector_type(4)))  float4;
+float4 test3(float4 x) {

bruno wrote:
> Can you also add a test for the `vector_type` variant? It might be more 
> appropriate to put this at test/Sema/ext_vector* and test/Sema/vector*
The test for the `vector_type` variant already exists in 
`test/Sema/vector-ops.c`. I tried to made similar test file for 
`ext_vector_type` by copying vector-ops.c and replacing vector types 
accordingly, but there are many differences in diagnostic, so only the part 
that checks the complement operation was copied.


https://reviews.llvm.org/D33732



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


[PATCH] D33732: Catch invalid bitwise operation on vector of floats

2017-06-04 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 101359.
sepavloff added a comment.

Updated regression test

The new regression test was obtained from Sema/vector-ops.c, the part of
it that checks binary complement was copied.


https://reviews.llvm.org/D33732

Files:
  lib/Sema/SemaExpr.cpp
  test/Sema/ext_vector_ops.c


Index: test/Sema/ext_vector_ops.c
===
--- /dev/null
+++ test/Sema/ext_vector_ops.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion -triple 
x86_64-apple-darwin10
+
+typedef unsigned int v2u __attribute__ ((ext_vector_type(2)));
+typedef int v2s __attribute__ ((ext_vector_type(2)));
+typedef float v2f __attribute__ ((ext_vector_type(2)));
+
+void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
+  // Bitwise binary operators
+  (void)(v2ua & v2ua);
+  (void)(v2fa & v2fa); // expected-error{{invalid operands to binary 
expression}}
+
+  // Unary operators
+  (void)(~v2ua);
+  (void)(~v2fa); // expected-error{{invalid argument type 'v2f' (vector of 2 
'float' values) to unary}}
+
+  // Comparison operators
+  v2sa = (v2ua==v2sa);
+
+  // Arrays
+  int array1[v2ua]; // expected-error{{size of array has non-integer type 
'v2u' (vector of 2 'unsigned int' values}}
+  int array2[17];
+  // FIXME: error message below needs type!
+  (void)(array2[v2ua]); // expected-error{{array subscript is not an integer}}
+
+  v2u *v2u_ptr = 0;
+  v2s *v2s_ptr;
+}
Index: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11953,16 +11953,13 @@
   << resultType << Input.get()->getSourceRange();
 else if (resultType->hasIntegerRepresentation())
   break;
-else if (resultType->isExtVectorType()) {
-  if (Context.getLangOpts().OpenCL) {
-// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
-// on vector float types.
-QualType T = resultType->getAs()->getElementType();
-if (!T->isIntegerType())
-  return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-   << resultType << Input.get()->getSourceRange());
-  }
-  break;
+else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
+  // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+  // on vector float types.
+  QualType T = resultType->getAs()->getElementType();
+  if (!T->isIntegerType())
+return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+  << resultType << Input.get()->getSourceRange());
 } else {
   return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());


Index: test/Sema/ext_vector_ops.c
===
--- /dev/null
+++ test/Sema/ext_vector_ops.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion -triple x86_64-apple-darwin10
+
+typedef unsigned int v2u __attribute__ ((ext_vector_type(2)));
+typedef int v2s __attribute__ ((ext_vector_type(2)));
+typedef float v2f __attribute__ ((ext_vector_type(2)));
+
+void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
+  // Bitwise binary operators
+  (void)(v2ua & v2ua);
+  (void)(v2fa & v2fa); // expected-error{{invalid operands to binary expression}}
+
+  // Unary operators
+  (void)(~v2ua);
+  (void)(~v2fa); // expected-error{{invalid argument type 'v2f' (vector of 2 'float' values) to unary}}
+
+  // Comparison operators
+  v2sa = (v2ua==v2sa);
+
+  // Arrays
+  int array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u' (vector of 2 'unsigned int' values}}
+  int array2[17];
+  // FIXME: error message below needs type!
+  (void)(array2[v2ua]); // expected-error{{array subscript is not an integer}}
+
+  v2u *v2u_ptr = 0;
+  v2s *v2s_ptr;
+}
Index: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11953,16 +11953,13 @@
   << resultType << Input.get()->getSourceRange();
 else if (resultType->hasIntegerRepresentation())
   break;
-else if (resultType->isExtVectorType()) {
-  if (Context.getLangOpts().OpenCL) {
-// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
-// on vector float types.
-QualType T = resultType->getAs()->getElementType();
-if (!T->isIntegerType())
-  return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-   << resultType << Input.get()->getSourceRange());
-  }
-  break;
+else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
+  // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+  // on vector float types.
+  QualType T = resultType->getAs()->getElementType();
+  if (!T->isInteger

[PATCH] D30170: Function definition may have uninstantiated body

2017-06-04 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 101362.
sepavloff added a comment.

Updated patch according to review notes


https://reviews.llvm.org/D30170

Files:
  include/clang/AST/Decl.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -101,6 +101,34 @@
   friend void func_12(int x = 0);  // expected-error{{friend declaration specifying a default argument must be the only declaration}}
 };
 
+// Friend function with uninstantiated body is still a definition.
+
+template struct C20 {
+  friend void func_20() {} // expected-note{{previous definition is here}}
+};
+C20 c20i;
+void func_20() {} // expected-error{{redefinition of 'func_20'}}
+
+template struct C21a {
+  friend void func_21() {} // expected-note{{previous definition is here}}
+};
+template struct C21b {
+  friend void func_21() {} // expected-error{{redefinition of 'func_21'}}
+};
+C21a c21ai;
+C21b c21bi; // expected-note{{in instantiation of template class 'C21b' requested here}}
+
+template struct C22a {
+  friend void func_22() {} // expected-note{{previous definition is here}}
+};
+template struct C22b {
+  friend void func_22();
+};
+C22a c22ai;
+C22b c22bi;
+void func_22() {} // expected-error{{redefinition of 'func_22'}}
+
+
 
 namespace pr22307 {
 
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1804,45 +1804,24 @@
 //   apply to non-template function declarations and definitions also apply
 //   to these implicit definitions.
 if (D->isThisDeclarationADefinition()) {
-  // Check for a function body.
-  const FunctionDecl *Definition = nullptr;
-  if (Function->isDefined(Definition) &&
-  Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
-SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
-<< Function->getDeclName();
-SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
-  }
-  // Check for redefinitions due to other instantiations of this or
-  // a similar friend function.
-  else for (auto R : Function->redecls()) {
-if (R == Function)
-  continue;
-
-// If some prior declaration of this function has been used, we need
-// to instantiate its definition.
-if (!QueuedInstantiation && R->isUsed(false)) {
-  if (MemberSpecializationInfo *MSInfo =
-  Function->getMemberSpecializationInfo()) {
-if (MSInfo->getPointOfInstantiation().isInvalid()) {
-  SourceLocation Loc = R->getLocation(); // FIXME
-  MSInfo->setPointOfInstantiation(Loc);
-  SemaRef.PendingLocalImplicitInstantiations.push_back(
-   std::make_pair(Function, Loc));
-  QueuedInstantiation = true;
-}
-  }
-}
-
-// If some prior declaration of this function was a friend with an
-// uninstantiated definition, reject it.
-if (R->getFriendObjectKind()) {
-  if (const FunctionDecl *RPattern =
-  R->getTemplateInstantiationPattern()) {
-if (RPattern->isDefined(RPattern)) {
-  SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
-<< Function->getDeclName();
-  SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
-  break;
+  SemaRef.CheckForFunctionRedefinition(Function);
+  if (!Function->isInvalidDecl()) {
+for (auto R : Function->redecls()) {
+  if (R == Function)
+continue;
+
+  // If some prior declaration of this function has been used, we need
+  // to instantiate its definition.
+  if (!QueuedInstantiation && R->isUsed(false)) {
+if (MemberSpecializationInfo *MSInfo =
+Function->getMemberSpecializationInfo()) {
+  if (MSInfo->getPointOfInstantiation().isInvalid()) {
+SourceLocation Loc = R->getLocation(); // FIXME
+MSInfo->setPointOfInstantiation(Loc);
+SemaRef.PendingLocalImplicitInstantiations.push_back(
+std::make_pair(Function, Loc));
+QueuedInstantiation = true;
+  }
 }
   }
 }
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11886,9 +11886,31 @@
const FunctionDecl *EffectiveDefinition,
SkipBodyInfo *SkipBody) {
   const FunctionDecl *Definition = EffectiveDefinition;
+  if (!Def

[PATCH] D30393: Do not inherit default arguments for friend function in class template.

2017-06-05 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 101512.
sepavloff added a comment.

Rebased patch


https://reviews.llvm.org/D30393

Files:
  lib/Sema/SemaDeclCXX.cpp
  test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp


Index: test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
===
--- test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
+++ test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
@@ -73,3 +73,36 @@
 }
 
 } // namespace
+
+namespace pr12724 {
+
+void func_01(bool param = true);
+class C01 {
+public:
+  friend void func_01(bool param);
+};
+
+void func_02(bool param = true);
+template
+class C02 {
+public:
+  friend void func_02(bool param);
+};
+C02 c02;
+
+void func_03(bool param);
+template
+class C03 {
+public:
+  friend void func_03(bool param);
+};
+void func_03(bool param = true);
+C03 c03;
+
+void main() {
+  func_01();
+  func_02();
+  func_03();
+}
+
+} // namespace pr12724
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -547,17 +547,23 @@
   Diag(OldParam->getLocation(), diag::note_previous_definition)
 << OldParam->getDefaultArgRange();
 } else if (OldParamHasDfl) {
-  // Merge the old default argument into the new parameter.
-  // It's important to use getInit() here;  getDefaultArg()
-  // strips off any top-level ExprWithCleanups.
-  NewParam->setHasInheritedDefaultArg();
-  if (OldParam->hasUnparsedDefaultArg())
-NewParam->setUnparsedDefaultArg();
-  else if (OldParam->hasUninstantiatedDefaultArg())
-NewParam->setUninstantiatedDefaultArg(
-  OldParam->getUninstantiatedDefaultArg());
-  else
-NewParam->setDefaultArg(OldParam->getInit());
+  // Merge the old default argument into the new parameter unless the new
+  // function is a friend declaration in a template class. In the latter
+  // case the default arguments will be inherited when the friend
+  // declaration will be instantiated.
+  if (New->getFriendObjectKind() == Decl::FOK_None ||
+  !New->getLexicalDeclContext()->isDependentContext()) {
+// It's important to use getInit() here;  getDefaultArg()
+// strips off any top-level ExprWithCleanups.
+NewParam->setHasInheritedDefaultArg();
+if (OldParam->hasUnparsedDefaultArg())
+  NewParam->setUnparsedDefaultArg();
+else if (OldParam->hasUninstantiatedDefaultArg())
+  NewParam->setUninstantiatedDefaultArg(
+   
OldParam->getUninstantiatedDefaultArg());
+else
+  NewParam->setDefaultArg(OldParam->getInit());
+  }
 } else if (NewParamHasDfl) {
   if (New->getDescribedFunctionTemplate()) {
 // Paragraph 4, quoted above, only applies to non-template functions.


Index: test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
===
--- test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
+++ test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
@@ -73,3 +73,36 @@
 }
 
 } // namespace
+
+namespace pr12724 {
+
+void func_01(bool param = true);
+class C01 {
+public:
+  friend void func_01(bool param);
+};
+
+void func_02(bool param = true);
+template
+class C02 {
+public:
+  friend void func_02(bool param);
+};
+C02 c02;
+
+void func_03(bool param);
+template
+class C03 {
+public:
+  friend void func_03(bool param);
+};
+void func_03(bool param = true);
+C03 c03;
+
+void main() {
+  func_01();
+  func_02();
+  func_03();
+}
+
+} // namespace pr12724
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -547,17 +547,23 @@
   Diag(OldParam->getLocation(), diag::note_previous_definition)
 << OldParam->getDefaultArgRange();
 } else if (OldParamHasDfl) {
-  // Merge the old default argument into the new parameter.
-  // It's important to use getInit() here;  getDefaultArg()
-  // strips off any top-level ExprWithCleanups.
-  NewParam->setHasInheritedDefaultArg();
-  if (OldParam->hasUnparsedDefaultArg())
-NewParam->setUnparsedDefaultArg();
-  else if (OldParam->hasUninstantiatedDefaultArg())
-NewParam->setUninstantiatedDefaultArg(
-  OldParam->getUninstantiatedDefaultArg());
-  else
-NewParam->setDefaultArg(OldParam->getInit());
+  // Merge the old default argument into the new parameter unless the new
+  // function is a friend declaration in a template class. In the latter
+  // case the default arguments will be inherited when the friend
+  // declaration will be instantiated.
+  if (New->getFriendObjectKind() == Decl::FOK_None ||
+  !New->getLexicalDeclContext()->isDepe

[PATCH] D30375: Function with unparsed body is a definition

2017-06-06 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 101517.
sepavloff added a comment.

Rebased patch


https://reviews.llvm.org/D30375

Files:
  include/clang/AST/Decl.h
  include/clang/Sema/Sema.h
  lib/Parse/Parser.cpp
  lib/Sema/SemaCUDA.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -170,3 +170,15 @@
 template class Test;
 
 }
+
+namespace pr14785 {
+template
+struct Somewhat {
+  void internal() const { }
+  friend void operator+(int const &, Somewhat const &) {}  // expected-error{{redefinition of 'operator+'}}
+};
+
+void operator+(int const &, Somewhat const &x) {  // expected-note {{previous definition is here}}
+  x.internal();  // expected-note{{in instantiation of template class 'pr14785::Somewhat' requested here}}
+}
+}
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3894,6 +3894,7 @@
 SubstQualifier(*this, PatternDecl, Function, TemplateArgs);
 
 ActOnStartOfFunctionDef(nullptr, Function);
+ActOnStartOfFunctionBody(Function);
 
 // Enter the scope of this instantiation. We don't use
 // PushDeclContext because we don't have a scope.
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12028,11 +12028,6 @@
   return D;
   }
 
-  // Mark this function as "will have a body eventually".  This lets users to
-  // call e.g. isInlineDefinitionExternallyVisible while we're still parsing
-  // this function.
-  FD->setWillHaveBody();
-
   // If we are instantiating a generic lambda call operator, push
   // a LambdaScopeInfo onto the function stack.  But use the information
   // that's already been calculated (ActOnLambdaExpr) to prime the current
@@ -12202,6 +12197,19 @@
   return Decl;
 }
 
+/// Semantic action called by parser when it expects that the current function
+/// definition will have a body statement.
+void Sema::ActOnStartOfFunctionBody(Decl *D) {
+  if (!D)
+return;
+  if (FunctionDecl *FD = dyn_cast(D)) {
+// Mark this function as "will have a body eventually".  This lets users to
+// call e.g. isInlineDefinitionExternallyVisible while we're still parsing
+// this function.
+FD->setWillHaveBody();
+  }
+}
+
 Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
   return ActOnFinishFunctionBody(D, BodyArg, false);
 }
Index: lib/Sema/SemaCUDA.cpp
===
--- lib/Sema/SemaCUDA.cpp
+++ lib/Sema/SemaCUDA.cpp
@@ -629,12 +629,6 @@
   // emitted, because (say) the definition could include "inline".
   FunctionDecl *Def = FD->getDefinition();
 
-  // We may currently be parsing the body of FD, in which case
-  // FD->getDefinition() will be null, but we still want to treat FD as though
-  // it's a definition.
-  if (!Def && FD->willHaveBody())
-Def = FD;
-
   if (Def &&
   !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def)))
 return true;
Index: lib/Parse/Parser.cpp
===
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -1186,6 +1186,8 @@
 return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
   }
 
+  Actions.ActOnStartOfFunctionBody(Res);
+
   if (Tok.is(tok::kw_try))
 return ParseFunctionTryBlock(Res, BodyScope);
 
Index: include/clang/Sema/Sema.h
===
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1981,6 +1981,7 @@
   bool canSkipFunctionBody(Decl *D);
 
   void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope);
+  void ActOnStartOfFunctionBody(Decl *Decl);
   Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
   Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
   Decl *ActOnSkippedFunctionBody(Decl *Decl);
Index: include/clang/AST/Decl.h
===
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1837,7 +1837,7 @@
   ///
   bool isThisDeclarationADefinition() const {
 return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
-  hasDefiningAttr();
+  WillHaveBody || hasDefiningAttr();
   }
 
   /// doesThisDeclarationHaveABody - Returns whether this specific
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D26065: Improve diagnostics if friend function redefines file-level function.

2017-06-06 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added inline comments.



Comment at: lib/Sema/SemaDeclCXX.cpp:646
+ // in this case, redefinition will be diagnosed later.
+ (New->isInlineSpecified() || !New->isOutOfLine() ||
+  !New->getLexicalDeclContext()->isRecord())) {

arphaman wrote:
> This is somewhat confusing to me: are you using the `!New->isOutOfLine() || 
> !New->getLexicalDeclContext()->isRecord()` check to ensure that this new 
> declaration is not a `friend`?
Indeed, this check is obscure. Replaced by call to `getFriendObjectKind`.


https://reviews.llvm.org/D26065



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


[PATCH] D26065: Improve diagnostics if friend function redefines file-level function.

2017-06-06 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 101666.
sepavloff added a comment.

Rebased and enhance check


https://reviews.llvm.org/D26065

Files:
  lib/Sema/SemaDeclCXX.cpp
  test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp


Index: test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
===
--- test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
+++ test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
@@ -4,3 +4,31 @@
 }
 
 inline void f0(); // expected-error {{inline declaration of 'f0' follows 
non-inline definition}}
+
+void func_01() {} // expected-note{{previous definition is here}}
+struct C01 {
+  friend void func_01() {} // expected-error{{redefinition of 'func_01'}}
+};
+
+void func_02() {} // expected-note{{previous definition is here}}
+struct C02 {
+  friend inline void func_02(); // expected-error{{inline declaration of 
'func_02' follows non-inline definition}}
+};
+
+void func_03() {} // expected-note{{previous definition is here}}
+struct C03 {
+  friend inline void func_03() {} // expected-error{{inline declaration of 
'func_03' follows non-inline definition}}
+};
+
+void func_04() {} // expected-note{{previous definition is here}}
+inline void func_04() {} // expected-error{{inline declaration of 'func_04' 
follows non-inline definition}}
+
+void func_06() {} // expected-note{{previous definition is here}}
+template struct C06 {
+  friend inline void func_06() {} // expected-error{{inline declaration of 
'func_06' follows non-inline definition}}
+};
+
+void func_07() {} // expected-note{{previous definition is here}}
+template struct C07 {
+  friend inline void func_07(); // expected-error{{inline declaration of 
'func_07' follows non-inline definition}}
+};
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -638,7 +638,12 @@
 Diag(Old->getLocation(), diag::note_previous_declaration);
 Invalid = true;
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
- Old->isDefined(Def)) {
+ Old->isDefined(Def) &&
+ // If a friend function is inlined but does not have 'inline'
+ // specifier, it is a definition. Do not report attribute conflict
+ // in this case, redefinition will be diagnosed later.
+ (New->isInlineSpecified() ||
+  New->getFriendObjectKind() == Decl::FOK_None)) {
 // C++11 [dcl.fcn.spec]p4:
 //   If the definition of a function appears in a translation unit before 
its
 //   first declaration as inline, the program is ill-formed.


Index: test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
===
--- test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
+++ test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
@@ -4,3 +4,31 @@
 }
 
 inline void f0(); // expected-error {{inline declaration of 'f0' follows non-inline definition}}
+
+void func_01() {} // expected-note{{previous definition is here}}
+struct C01 {
+  friend void func_01() {} // expected-error{{redefinition of 'func_01'}}
+};
+
+void func_02() {} // expected-note{{previous definition is here}}
+struct C02 {
+  friend inline void func_02(); // expected-error{{inline declaration of 'func_02' follows non-inline definition}}
+};
+
+void func_03() {} // expected-note{{previous definition is here}}
+struct C03 {
+  friend inline void func_03() {} // expected-error{{inline declaration of 'func_03' follows non-inline definition}}
+};
+
+void func_04() {} // expected-note{{previous definition is here}}
+inline void func_04() {} // expected-error{{inline declaration of 'func_04' follows non-inline definition}}
+
+void func_06() {} // expected-note{{previous definition is here}}
+template struct C06 {
+  friend inline void func_06() {} // expected-error{{inline declaration of 'func_06' follows non-inline definition}}
+};
+
+void func_07() {} // expected-note{{previous definition is here}}
+template struct C07 {
+  friend inline void func_07(); // expected-error{{inline declaration of 'func_07' follows non-inline definition}}
+};
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -638,7 +638,12 @@
 Diag(Old->getLocation(), diag::note_previous_declaration);
 Invalid = true;
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
- Old->isDefined(Def)) {
+ Old->isDefined(Def) &&
+ // If a friend function is inlined but does not have 'inline'
+ // specifier, it is a definition. Do not report attribute conflict
+ // in this case, redefinition will be diagnosed later.
+ (New->isInlineSpecified() ||
+  New->getFriendObjectKind() == Decl::FOK_None)) {
 // C++11 [dcl.fcn.spec]p4:
 //   If the definition of a

[PATCH] D33732: Catch invalid bitwise operation on vector of floats

2017-06-07 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL304963: Catch invalid bitwise operation on vector of floats 
(authored by sepavloff).

Changed prior to commit:
  https://reviews.llvm.org/D33732?vs=101359&id=101856#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D33732

Files:
  cfe/trunk/lib/Sema/SemaExpr.cpp
  cfe/trunk/test/Sema/ext_vector_ops.c


Index: cfe/trunk/test/Sema/ext_vector_ops.c
===
--- cfe/trunk/test/Sema/ext_vector_ops.c
+++ cfe/trunk/test/Sema/ext_vector_ops.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion -triple 
x86_64-apple-darwin10
+
+typedef unsigned int v2u __attribute__ ((ext_vector_type(2)));
+typedef int v2s __attribute__ ((ext_vector_type(2)));
+typedef float v2f __attribute__ ((ext_vector_type(2)));
+
+void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
+  // Bitwise binary operators
+  (void)(v2ua & v2ua);
+  (void)(v2fa & v2fa); // expected-error{{invalid operands to binary 
expression}}
+
+  // Unary operators
+  (void)(~v2ua);
+  (void)(~v2fa); // expected-error{{invalid argument type 'v2f' (vector of 2 
'float' values) to unary}}
+
+  // Comparison operators
+  v2sa = (v2ua==v2sa);
+
+  // Arrays
+  int array1[v2ua]; // expected-error{{size of array has non-integer type 
'v2u' (vector of 2 'unsigned int' values}}
+  int array2[17];
+  // FIXME: error message below needs type!
+  (void)(array2[v2ua]); // expected-error{{array subscript is not an integer}}
+
+  v2u *v2u_ptr = 0;
+  v2s *v2s_ptr;
+}
Index: cfe/trunk/lib/Sema/SemaExpr.cpp
===
--- cfe/trunk/lib/Sema/SemaExpr.cpp
+++ cfe/trunk/lib/Sema/SemaExpr.cpp
@@ -11975,16 +11975,13 @@
   << resultType << Input.get()->getSourceRange();
 else if (resultType->hasIntegerRepresentation())
   break;
-else if (resultType->isExtVectorType()) {
-  if (Context.getLangOpts().OpenCL) {
-// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
-// on vector float types.
-QualType T = resultType->getAs()->getElementType();
-if (!T->isIntegerType())
-  return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-   << resultType << Input.get()->getSourceRange());
-  }
-  break;
+else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
+  // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+  // on vector float types.
+  QualType T = resultType->getAs()->getElementType();
+  if (!T->isIntegerType())
+return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+  << resultType << Input.get()->getSourceRange());
 } else {
   return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());


Index: cfe/trunk/test/Sema/ext_vector_ops.c
===
--- cfe/trunk/test/Sema/ext_vector_ops.c
+++ cfe/trunk/test/Sema/ext_vector_ops.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion -triple x86_64-apple-darwin10
+
+typedef unsigned int v2u __attribute__ ((ext_vector_type(2)));
+typedef int v2s __attribute__ ((ext_vector_type(2)));
+typedef float v2f __attribute__ ((ext_vector_type(2)));
+
+void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
+  // Bitwise binary operators
+  (void)(v2ua & v2ua);
+  (void)(v2fa & v2fa); // expected-error{{invalid operands to binary expression}}
+
+  // Unary operators
+  (void)(~v2ua);
+  (void)(~v2fa); // expected-error{{invalid argument type 'v2f' (vector of 2 'float' values) to unary}}
+
+  // Comparison operators
+  v2sa = (v2ua==v2sa);
+
+  // Arrays
+  int array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u' (vector of 2 'unsigned int' values}}
+  int array2[17];
+  // FIXME: error message below needs type!
+  (void)(array2[v2ua]); // expected-error{{array subscript is not an integer}}
+
+  v2u *v2u_ptr = 0;
+  v2s *v2s_ptr;
+}
Index: cfe/trunk/lib/Sema/SemaExpr.cpp
===
--- cfe/trunk/lib/Sema/SemaExpr.cpp
+++ cfe/trunk/lib/Sema/SemaExpr.cpp
@@ -11975,16 +11975,13 @@
   << resultType << Input.get()->getSourceRange();
 else if (resultType->hasIntegerRepresentation())
   break;
-else if (resultType->isExtVectorType()) {
-  if (Context.getLangOpts().OpenCL) {
-// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
-// on vector float types.
-QualType T = resultType->getAs()->getElementType();
-if (!T->isIntegerType())
-  return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-   << resultType << Input.get()->getSourceRange());
-  }
-  break;
+else if (resultType->isExt

[PATCH] D26065: Improve diagnostics if friend function redefines file-level function.

2017-06-07 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL304964: Improve diagnostics if friend function redefines 
file-level function. (authored by sepavloff).

Changed prior to commit:
  https://reviews.llvm.org/D26065?vs=101666&id=101859#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D26065

Files:
  cfe/trunk/lib/Sema/SemaDeclCXX.cpp
  cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp


Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
===
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp
@@ -638,7 +638,12 @@
 Diag(Old->getLocation(), diag::note_previous_declaration);
 Invalid = true;
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
- Old->isDefined(Def)) {
+ Old->isDefined(Def) &&
+ // If a friend function is inlined but does not have 'inline'
+ // specifier, it is a definition. Do not report attribute conflict
+ // in this case, redefinition will be diagnosed later.
+ (New->isInlineSpecified() ||
+  New->getFriendObjectKind() == Decl::FOK_None)) {
 // C++11 [dcl.fcn.spec]p4:
 //   If the definition of a function appears in a translation unit before 
its
 //   first declaration as inline, the program is ill-formed.
Index: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
===
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
@@ -4,3 +4,31 @@
 }
 
 inline void f0(); // expected-error {{inline declaration of 'f0' follows 
non-inline definition}}
+
+void func_01() {} // expected-note{{previous definition is here}}
+struct C01 {
+  friend void func_01() {} // expected-error{{redefinition of 'func_01'}}
+};
+
+void func_02() {} // expected-note{{previous definition is here}}
+struct C02 {
+  friend inline void func_02(); // expected-error{{inline declaration of 
'func_02' follows non-inline definition}}
+};
+
+void func_03() {} // expected-note{{previous definition is here}}
+struct C03 {
+  friend inline void func_03() {} // expected-error{{inline declaration of 
'func_03' follows non-inline definition}}
+};
+
+void func_04() {} // expected-note{{previous definition is here}}
+inline void func_04() {} // expected-error{{inline declaration of 'func_04' 
follows non-inline definition}}
+
+void func_06() {} // expected-note{{previous definition is here}}
+template struct C06 {
+  friend inline void func_06() {} // expected-error{{inline declaration of 
'func_06' follows non-inline definition}}
+};
+
+void func_07() {} // expected-note{{previous definition is here}}
+template struct C07 {
+  friend inline void func_07(); // expected-error{{inline declaration of 
'func_07' follows non-inline definition}}
+};


Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
===
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp
@@ -638,7 +638,12 @@
 Diag(Old->getLocation(), diag::note_previous_declaration);
 Invalid = true;
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
- Old->isDefined(Def)) {
+ Old->isDefined(Def) &&
+ // If a friend function is inlined but does not have 'inline'
+ // specifier, it is a definition. Do not report attribute conflict
+ // in this case, redefinition will be diagnosed later.
+ (New->isInlineSpecified() ||
+  New->getFriendObjectKind() == Decl::FOK_None)) {
 // C++11 [dcl.fcn.spec]p4:
 //   If the definition of a function appears in a translation unit before its
 //   first declaration as inline, the program is ill-formed.
Index: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
===
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
@@ -4,3 +4,31 @@
 }
 
 inline void f0(); // expected-error {{inline declaration of 'f0' follows non-inline definition}}
+
+void func_01() {} // expected-note{{previous definition is here}}
+struct C01 {
+  friend void func_01() {} // expected-error{{redefinition of 'func_01'}}
+};
+
+void func_02() {} // expected-note{{previous definition is here}}
+struct C02 {
+  friend inline void func_02(); // expected-error{{inline declaration of 'func_02' follows non-inline definition}}
+};
+
+void func_03() {} // expected-note{{previous definition is here}}
+struct C03 {
+  friend inline void func_03() {} // expected-error{{inline declaration of 'func_03' follows non-inline definition}}
+};
+
+void func_04() {} // expected-note{{previous definition is here}}
+inline void func_04() {} // expected-error{{inline declaration of 'func_04' 

[PATCH] D30393: Do not inherit default arguments for friend function in class template.

2017-06-07 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL304965: Do not inherit default arguments for friend function 
in class template. (authored by sepavloff).

Changed prior to commit:
  https://reviews.llvm.org/D30393?vs=101512&id=101861#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D30393

Files:
  cfe/trunk/lib/Sema/SemaDeclCXX.cpp
  cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp


Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
===
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp
@@ -547,17 +547,23 @@
   Diag(OldParam->getLocation(), diag::note_previous_definition)
 << OldParam->getDefaultArgRange();
 } else if (OldParamHasDfl) {
-  // Merge the old default argument into the new parameter.
-  // It's important to use getInit() here;  getDefaultArg()
-  // strips off any top-level ExprWithCleanups.
-  NewParam->setHasInheritedDefaultArg();
-  if (OldParam->hasUnparsedDefaultArg())
-NewParam->setUnparsedDefaultArg();
-  else if (OldParam->hasUninstantiatedDefaultArg())
-NewParam->setUninstantiatedDefaultArg(
-  OldParam->getUninstantiatedDefaultArg());
-  else
-NewParam->setDefaultArg(OldParam->getInit());
+  // Merge the old default argument into the new parameter unless the new
+  // function is a friend declaration in a template class. In the latter
+  // case the default arguments will be inherited when the friend
+  // declaration will be instantiated.
+  if (New->getFriendObjectKind() == Decl::FOK_None ||
+  !New->getLexicalDeclContext()->isDependentContext()) {
+// It's important to use getInit() here;  getDefaultArg()
+// strips off any top-level ExprWithCleanups.
+NewParam->setHasInheritedDefaultArg();
+if (OldParam->hasUnparsedDefaultArg())
+  NewParam->setUnparsedDefaultArg();
+else if (OldParam->hasUninstantiatedDefaultArg())
+  NewParam->setUninstantiatedDefaultArg(
+   
OldParam->getUninstantiatedDefaultArg());
+else
+  NewParam->setDefaultArg(OldParam->getInit());
+  }
 } else if (NewParamHasDfl) {
   if (New->getDescribedFunctionTemplate()) {
 // Paragraph 4, quoted above, only applies to non-template functions.
Index: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
===
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
@@ -73,3 +73,36 @@
 }
 
 } // namespace
+
+namespace pr12724 {
+
+void func_01(bool param = true);
+class C01 {
+public:
+  friend void func_01(bool param);
+};
+
+void func_02(bool param = true);
+template
+class C02 {
+public:
+  friend void func_02(bool param);
+};
+C02 c02;
+
+void func_03(bool param);
+template
+class C03 {
+public:
+  friend void func_03(bool param);
+};
+void func_03(bool param = true);
+C03 c03;
+
+void main() {
+  func_01();
+  func_02();
+  func_03();
+}
+
+} // namespace pr12724


Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
===
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp
@@ -547,17 +547,23 @@
   Diag(OldParam->getLocation(), diag::note_previous_definition)
 << OldParam->getDefaultArgRange();
 } else if (OldParamHasDfl) {
-  // Merge the old default argument into the new parameter.
-  // It's important to use getInit() here;  getDefaultArg()
-  // strips off any top-level ExprWithCleanups.
-  NewParam->setHasInheritedDefaultArg();
-  if (OldParam->hasUnparsedDefaultArg())
-NewParam->setUnparsedDefaultArg();
-  else if (OldParam->hasUninstantiatedDefaultArg())
-NewParam->setUninstantiatedDefaultArg(
-  OldParam->getUninstantiatedDefaultArg());
-  else
-NewParam->setDefaultArg(OldParam->getInit());
+  // Merge the old default argument into the new parameter unless the new
+  // function is a friend declaration in a template class. In the latter
+  // case the default arguments will be inherited when the friend
+  // declaration will be instantiated.
+  if (New->getFriendObjectKind() == Decl::FOK_None ||
+  !New->getLexicalDeclContext()->isDependentContext()) {
+// It's important to use getInit() here;  getDefaultArg()
+// strips off any top-level ExprWithCleanups.
+NewParam->setHasInheritedDefaultArg();
+if (OldParam->hasUnparsedDefaultArg())
+  NewParam->setUnparsedDefaultArg();
+else if (OldParam->hasUninstantiatedDefaultArg())
+  NewParam->setUninstantiatedDefaultArg(
+ 

[PATCH] D30375: Function with unparsed body is a definition

2017-06-08 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Thank you for explanation. Probably making new semantic action is an overkill.

The intent was to postpone setting flag `WillHaveBody` as late as possible, to 
the moment when it becomes clear that the function indeed will have a body. 
Otherwise parsing of deleted functions is broken. Also in the case of invalid 
input the resulting function declaration become definition while previously 
they were not, it also changes existing behavior. The new semantic action set 
the flag enough late after the call to `ActOnStartOfFunctionBody`, when this 
treatment is already made.

The new solution uses different path. As previously, `ActOnStartOfFunctionBody` 
sets `WillHaveBody` but this flag is reset when it becomes clear that body will 
be available. Such technique is already uses for defaulted functions, so only 
deleted require the flag reset. `WillHaveBody` is also reset when parsing of 
function is finished. This transient flag is not needed after the function 
parsing is done. If `ActOnFinishFunctionBody` is always  called after 
`ActOnStartOfFunctionBody`, erroneous functions are not leaked as definition.


https://reviews.llvm.org/D30375



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


[PATCH] D30375: Function with unparsed body is a definition

2017-06-08 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 101993.
sepavloff added a comment.

Changed implementation


https://reviews.llvm.org/D30375

Files:
  include/clang/AST/Decl.h
  lib/Sema/SemaCUDA.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -170,3 +170,15 @@
 template class Test;
 
 }
+
+namespace pr14785 {
+template
+struct Somewhat {
+  void internal() const { }
+  friend void operator+(int const &, Somewhat const &) {}  // expected-error{{redefinition of 'operator+'}}
+};
+
+void operator+(int const &, Somewhat const &x) {  // expected-note {{previous definition is here}}
+  x.internal();  // expected-note{{in instantiation of template class 'pr14785::Somewhat' requested here}}
+}
+}
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1782,6 +1782,12 @@
   Previous.clear();
   }
 
+  if (isFriend) {
+Function->setObjectOfFriendDecl();
+if (FunctionTemplate)
+  FunctionTemplate->setObjectOfFriendDecl();
+  }
+
   SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
isExplicitSpecialization);
 
@@ -1792,7 +1798,6 @@
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-PrincipalDecl->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -13878,6 +13878,9 @@
 return;
   }
 
+  // Deleted function does not have a body.
+  Fn->setWillHaveBody(false);
+
   if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
 // Don't consider the implicit declaration we generate for explicit
 // specializations. FIXME: Do not generate these implicit declarations.
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12218,6 +12218,7 @@
 
   if (FD) {
 FD->setBody(Body);
+FD->setWillHaveBody(false);
 
 if (getLangOpts().CPlusPlus14) {
   if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
Index: lib/Sema/SemaCUDA.cpp
===
--- lib/Sema/SemaCUDA.cpp
+++ lib/Sema/SemaCUDA.cpp
@@ -629,12 +629,6 @@
   // emitted, because (say) the definition could include "inline".
   FunctionDecl *Def = FD->getDefinition();
 
-  // We may currently be parsing the body of FD, in which case
-  // FD->getDefinition() will be null, but we still want to treat FD as though
-  // it's a definition.
-  if (!Def && FD->willHaveBody())
-Def = FD;
-
   if (Def &&
   !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def)))
 return true;
Index: include/clang/AST/Decl.h
===
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1837,7 +1837,7 @@
   ///
   bool isThisDeclarationADefinition() const {
 return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
-  hasDefiningAttr();
+  WillHaveBody || hasDefiningAttr();
   }
 
   /// doesThisDeclarationHaveABody - Returns whether this specific
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D30375: Function with unparsed body is a definition

2017-06-14 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL305379: Function with unparsed body is a definition 
(authored by sepavloff).

Changed prior to commit:
  https://reviews.llvm.org/D30375?vs=101993&id=102512#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D30375

Files:
  cfe/trunk/include/clang/AST/Decl.h
  cfe/trunk/lib/Sema/SemaCUDA.cpp
  cfe/trunk/lib/Sema/SemaDecl.cpp
  cfe/trunk/lib/Sema/SemaDeclCXX.cpp
  cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
  cfe/trunk/test/SemaCXX/friend2.cpp

Index: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1782,6 +1782,12 @@
   Previous.clear();
   }
 
+  if (isFriend) {
+Function->setObjectOfFriendDecl();
+if (FunctionTemplate)
+  FunctionTemplate->setObjectOfFriendDecl();
+  }
+
   SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
isExplicitSpecialization);
 
@@ -1792,7 +1798,6 @@
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-PrincipalDecl->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: cfe/trunk/lib/Sema/SemaDecl.cpp
===
--- cfe/trunk/lib/Sema/SemaDecl.cpp
+++ cfe/trunk/lib/Sema/SemaDecl.cpp
@@ -12218,6 +12218,7 @@
 
   if (FD) {
 FD->setBody(Body);
+FD->setWillHaveBody(false);
 
 if (getLangOpts().CPlusPlus14) {
   if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
===
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp
@@ -13878,6 +13878,9 @@
 return;
   }
 
+  // Deleted function does not have a body.
+  Fn->setWillHaveBody(false);
+
   if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
 // Don't consider the implicit declaration we generate for explicit
 // specializations. FIXME: Do not generate these implicit declarations.
Index: cfe/trunk/lib/Sema/SemaCUDA.cpp
===
--- cfe/trunk/lib/Sema/SemaCUDA.cpp
+++ cfe/trunk/lib/Sema/SemaCUDA.cpp
@@ -629,12 +629,6 @@
   // emitted, because (say) the definition could include "inline".
   FunctionDecl *Def = FD->getDefinition();
 
-  // We may currently be parsing the body of FD, in which case
-  // FD->getDefinition() will be null, but we still want to treat FD as though
-  // it's a definition.
-  if (!Def && FD->willHaveBody())
-Def = FD;
-
   if (Def &&
   !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def)))
 return true;
Index: cfe/trunk/include/clang/AST/Decl.h
===
--- cfe/trunk/include/clang/AST/Decl.h
+++ cfe/trunk/include/clang/AST/Decl.h
@@ -1872,7 +1872,7 @@
   ///
   bool isThisDeclarationADefinition() const {
 return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
-  hasDefiningAttr();
+  WillHaveBody || hasDefiningAttr();
   }
 
   /// doesThisDeclarationHaveABody - Returns whether this specific
Index: cfe/trunk/test/SemaCXX/friend2.cpp
===
--- cfe/trunk/test/SemaCXX/friend2.cpp
+++ cfe/trunk/test/SemaCXX/friend2.cpp
@@ -170,3 +170,15 @@
 template class Test;
 
 }
+
+namespace pr14785 {
+template
+struct Somewhat {
+  void internal() const { }
+  friend void operator+(int const &, Somewhat const &) {}  // expected-error{{redefinition of 'operator+'}}
+};
+
+void operator+(int const &, Somewhat const &x) {  // expected-note {{previous definition is here}}
+  x.internal();  // expected-note{{in instantiation of template class 'pr14785::Somewhat' requested here}}
+}
+}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D30375: Function with unparsed body is a definition

2017-06-14 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Thank you!
Committed as is, improvements will be made as separate patches.


Repository:
  rL LLVM

https://reviews.llvm.org/D30375



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


[PATCH] D30375: Function with unparsed body is a definition

2017-06-21 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Initial commit (r305379) was reverted (r305381) because it broke self builds. 
The reason was not related to the WillHaveBody flag but was due to the change:

  if (isFriend) {
Function->setObjectOfFriendDecl();
if (FunctionTemplate)
  FunctionTemplate->setObjectOfFriendDecl();
  }

Attempt to execute `FunctionTemplate->setObjectOfFriendDecl()` caused assertion 
violation because the declaration had `IDNS_NonMemberOperator` in its 
IdentifierNamespace. There is nothing wrong with this flag, 
`setObjectOfFriendDecl` must be updated accordingly. This is however a problem 
of friend function templates, it will be addressed in other patch. For now the 
call to  `setObjectOfFriendDecl` is made as previously, with the exception that 
it is called for `Function` prior to call to `CheckFunctionDeclaration`, as it 
is necessary for proper diagnostics.


Repository:
  rL LLVM

https://reviews.llvm.org/D30375



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


[PATCH] D41189: [Frontend] Treat function with skipped body as definition

2017-12-13 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff accepted this revision.
sepavloff added a comment.
This revision is now accepted and ready to land.

LGTM.

Thanks!


Repository:
  rC Clang

https://reviews.llvm.org/D41189



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


[PATCH] D24933: Enable configuration files in clang

2017-12-15 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 127109.
sepavloff added a comment.

Updated patch

Fixed cmake config file definition.
Use llvm::sys::fs::make_absolute to get absolute path.


https://reviews.llvm.org/D24933

Files:
  docs/UsersManual.rst
  include/clang/Basic/DiagnosticDriverKinds.td
  include/clang/Config/config.h.cmake
  include/clang/Driver/Driver.h
  include/clang/Driver/Options.td
  lib/Driver/Driver.cpp
  test/Driver/Inputs/config-1.cfg
  test/Driver/Inputs/config-2.cfg
  test/Driver/Inputs/config-2a.cfg
  test/Driver/Inputs/config-3.cfg
  test/Driver/Inputs/config-4.cfg
  test/Driver/Inputs/config-5.cfg
  test/Driver/Inputs/config-6.cfg
  test/Driver/Inputs/config/config-4.cfg
  test/Driver/Inputs/config/i386-qqq.cfg
  test/Driver/Inputs/config/i386-qqq3.cfg
  test/Driver/Inputs/config/x86_64-qqq.cfg
  test/Driver/Inputs/config/x86_64-qqq2.cfg
  test/Driver/Inputs/config/x86_64.cfg
  test/Driver/Inputs/config2/config-4.cfg
  test/Driver/Inputs/config2/i386.cfg
  test/Driver/config-file-errs.c
  test/Driver/config-file.c
  test/Driver/config-file2.c
  test/Driver/config-file3.c

Index: test/Driver/config-file3.c
===
--- /dev/null
+++ test/Driver/config-file3.c
@@ -0,0 +1,98 @@
+// REQUIRES: shell
+// REQUIRES: x86-registered-target
+
+//--- If config file is specified by relative path (workdir/cfg-s2), it is searched for by that path.
+//
+// RUN: mkdir -p %T/workdir
+// RUN: echo "@subdir/cfg-s2" > %T/workdir/cfg-1
+// RUN: mkdir -p %T/workdir/subdir
+// RUN: echo "-Wundefined-var-template" > %T/workdir/subdir/cfg-s2
+//
+// RUN: ( cd %T && %clang --config workdir/cfg-1 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-REL )
+//
+// CHECK-REL: Configuration file: {{.*}}/workdir/cfg-1
+// CHECK-REL: -Wundefined-var-template
+
+
+//--- Invocation qqq-clang-g++ tries to find config file qqq-clang-g++.cfg first.
+//
+// RUN: mkdir -p %T/testdmode
+// RUN: [ ! -s %T/testdmode/qqq-clang-g++ ] || rm %T/testdmode/qqq-clang-g++
+// RUN: ln -s %clang %T/testdmode/qqq-clang-g++
+// RUN: echo "-Wundefined-func-template" > %T/testdmode/qqq-clang-g++.cfg
+// RUN: echo "-Werror" > %T/testdmode/qqq.cfg
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir= -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix FULL-NAME
+//
+// FULL-NAME: Configuration file: {{.*}}/testdmode/qqq-clang-g++.cfg
+// FULL-NAME: -Wundefined-func-template
+// FULL-NAME-NOT: -Werror
+//
+//--- File specified by --config overrides config inferred from clang executable.
+//
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --config i386-qqq -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-EXPLICIT
+//
+// CHECK-EXPLICIT: Configuration file: {{.*}}/Inputs/config/i386-qqq.cfg
+//
+//--- Invocation qqq-clang-g++ tries to find config file qqq.cfg if qqq-clang-g++.cfg is not found.
+//
+// RUN: rm %T/testdmode/qqq-clang-g++.cfg
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir= -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix SHORT-NAME
+//
+// SHORT-NAME: Configuration file: {{.*}}/testdmode/qqq.cfg
+// SHORT-NAME: -Werror
+// SHORT-NAME-NOT: -Wundefined-func-template
+
+
+//--- Config files are searched for in binary directory as well.
+//
+// RUN: mkdir -p %T/testbin
+// RUN: [ ! -s %T/testbin/clang ] || rm %T/testbin/clang
+// RUN: ln -s %clang %T/testbin/clang
+// RUN: echo "-Werror" > %T/testbin/aaa.cfg
+// RUN: %T/testbin/clang --config-system-dir= --config-user-dir= --config aaa.cfg -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-BIN
+//
+// CHECK-BIN: Configuration file: {{.*}}/testbin/aaa.cfg
+// CHECK-BIN: -Werror
+
+
+//--- If command line contains options that change triple (for instance, -m32), clang tries
+//reloading config file.
+
+//--- When reloading config file, x86_64-clang-g++ tries to find config i386-clang-g++.cfg first.
+//
+// RUN: mkdir -p %T/testreload
+// RUN: [ ! -s %T/testreload/x86_64-clang-g++ ] || rm %T/testreload/x86_64-clang-g++
+// RUN: ln -s %clang %T/testreload/x86_64-clang-g++
+// RUN: echo "-Wundefined-func-template" > %T/testreload/i386-clang-g++.cfg
+// RUN: echo "-Werror" > %T/testreload/i386.cfg
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir= --config-user-dir= -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD
+//
+// CHECK-RELOAD: Configuration file: {{.*}}/testreload/i386-clang-g++.cfg
+// CHECK-RELOAD: -Wundefined-func-template
+// CHECK-RELOAD-NOT: -Werror
+
+//--- If config file is specified by --config and its name does not start with architecture, it is used without reloading.
+//
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir=%S/Inputs --config-user-dir= --config config-3 -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD1a
+//
+// CHECK-RELOAD1a: Config

[PATCH] D24933: Enable configuration files in clang

2017-12-15 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked 2 inline comments as done.
sepavloff added inline comments.



Comment at: include/clang/Config/config.h.cmake:40
+#cmakedefine CLANG_CONFIG_FILE_SYSTEM_DIR ${CLANG_CONFIG_FILE_SYSTEM_DIR}
+#cmakedefine CLANG_CONFIG_FILE_USER_DIR ${CLANG_CONFIG_FILE_USER_DIR}
+

hintonda wrote:
> These need to be in quotes since you assign them to a std::string, i.e.:
> 
> ```
> #cmakedefine CLANG_CONFIG_FILE_SYSTEM_DIR "${CLANG_CONFIG_FILE_SYSTEM_DIR}"
> #cmakedefine CLANG_CONFIG_FILE_USER_DIR "${CLANG_CONFIG_FILE_USER_DIR}"
> ```
Fixed, thank you.



Comment at: lib/Driver/Driver.cpp:641
+
+static std::string getAbsolutePath(StringRef P) {
+  if (P.empty())

hfinkel wrote:
> Use llvm::sys::fs::make_absolute instead of this.
Removed `getAbsolutePath`.


https://reviews.llvm.org/D24933



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


[PATCH] D41179: [Sema] Diagnose template specializations with C linkage

2017-12-17 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Is it correct to emit error in this case?

According to the Standard 10.5p1 "All function types, function names with 
external linkage, and variable names with external linkage have a language 
linkage". So templates do not have a language linkage.
The next paragraph, which introduces inkage-specification, states: "The 
string-literal indicates the required language linkage". So the construct 
`extern "C"`  specifies just language linkage, which is not pertinent to 
templates.

In 10.5p4 there is an example of a class defined in extern "C" construct:

  extern "C" {
class X {
  void mf(); // the name of the function mf and the member function’s type 
have
 // C++ language linkage
  void mf2(void(*)()); // the name of the function mf2 has C++ language 
linkage;
   // the parameter has type “pointer to C function”
};
  }

Classes do not have language linkage according to 10.5p1, just as templates, so 
this code is valid.

It looks like defining templates inside extern "C" blocks is OK.


https://reviews.llvm.org/D41179



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


[PATCH] D41237: [Frontend] Handle skipped bodies in template instantiations

2017-12-18 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added inline comments.



Comment at: lib/Sema/SemaDecl.cpp:12184
 Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
-  if (FunctionDecl *FD = dyn_cast_or_null(Decl))
+  if (FunctionDecl *FD = Decl->getAsFunction())
 FD->setHasSkippedBody();

In the case of `Decl == nullptr` this code would crash. Probably it makes sense 
to check for this condition at the beginning of the function and use `dyn_cast` 
instead of `dyn_cast_or_null` in the next check.



Repository:
  rC Clang

https://reviews.llvm.org/D41237



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


[PATCH] D41433: Unit tests for TBAA metadata generation.

2017-12-20 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: rjmccall, hfinkel.
Herald added subscribers: kosarev, mgorny.

Now tests for metadata created by clang involve compiling code snippets
placed into c/c++ source files and matching interesting patterns in the
obtained textual representation of IR. Writting such tests is a painful
process as metadata often form complex tree-like structures but textual
representation of IR contains only a pile of metadata at the module end.

This change implements IR matchers that may be used to match required
patterns in the binary IR representation. In this case the metadata
structure is not broken and creation of match patterns is easier.

The change adds unit tests for TBAA metadata generation.


Repository:
  rC Clang

https://reviews.llvm.org/D41433

Files:
  unittests/CodeGen/CMakeLists.txt
  unittests/CodeGen/IRMatchers.h
  unittests/CodeGen/TBAAMetadataTest.cpp

Index: unittests/CodeGen/TBAAMetadataTest.cpp
===
--- /dev/null
+++ unittests/CodeGen/TBAAMetadataTest.cpp
@@ -0,0 +1,1299 @@
+//=== unittests/CodeGen/TBAAMetadataTest.cpp - Checks metadata generation -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "IRMatchers.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Parse/ParseAST.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+#include 
+
+using namespace llvm;
+
+namespace {
+
+struct TestCompiler {
+  LLVMContext Context;
+  clang::CompilerInstance compiler;
+  clang::CodeGenerator *CG = nullptr;
+  llvm::Module *M = nullptr;
+  unsigned PtrSize = 0;
+
+  void init(const char *TestProgram) {
+compiler.createDiagnostics();
+compiler.getCodeGenOpts().StructPathTBAA = 1;
+compiler.getCodeGenOpts().OptimizationLevel = 1;
+
+std::string TrStr = llvm::Triple::normalize(llvm::sys::getProcessTriple());
+llvm::Triple Tr(TrStr);
+Tr.setOS(Triple::Linux);
+Tr.setVendor(Triple::VendorType::UnknownVendor);
+Tr.setEnvironment(Triple::EnvironmentType::UnknownEnvironment);
+compiler.getTargetOpts().Triple = Tr.getTriple();
+compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
+compiler.getDiagnostics(),
+std::make_shared(compiler.getTargetOpts(;
+
+const clang::TargetInfo &TInfo = compiler.getTarget();
+PtrSize = TInfo.getPointerWidth(0) / 8;
+
+compiler.createFileManager();
+compiler.createSourceManager(compiler.getFileManager());
+compiler.createPreprocessor(clang::TU_Prefix);
+
+compiler.createASTContext();
+
+CG = CreateLLVMCodeGen(
+compiler.getDiagnostics(),
+"main-module",
+compiler.getHeaderSearchOpts(),
+compiler.getPreprocessorOpts(),
+compiler.getCodeGenOpts(),
+Context);
+compiler.setASTConsumer(std::unique_ptr(CG));
+
+compiler.createSema(clang::TU_Prefix, nullptr);
+
+clang::SourceManager &sm = compiler.getSourceManager();
+sm.setMainFileID(sm.createFileID(
+llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
+  }
+
+  const BasicBlock *compile() {
+clang::ParseAST(compiler.getSema(), false, false);
+M = CG->GetModule();
+
+// Do not expect more than one function definition.
+auto FuncPtr = M->begin();
+for (; FuncPtr != M->end(); ++FuncPtr)
+  if (!FuncPtr->isDeclaration())
+break;
+assert(FuncPtr != M->end());
+const llvm::Function &Func = *FuncPtr;
+++FuncPtr;
+for (; FuncPtr != M->end(); ++FuncPtr)
+  if (!FuncPtr->isDeclaration())
+break;
+assert(FuncPtr == M->end());
+
+// The function must consist of single basic block.
+auto BBPtr = Func.begin();
+assert(Func.begin() != Func.end());
+const BasicBlock &BB = *BBPtr;
+++BBPtr;
+assert(BBPtr == Func.end());
+
+return &BB;
+  }
+};
+
+
+auto OmnipotentCharC = MMTuple(
+  MMString("omnipotent char"),
+  MMTuple(
+MMString("Simple C/C++ TBAA")),
+  MConstInt(0, 64)
+);
+
+
+auto OmnipotentCharCXX = MMTuple(
+  MMString("omnipotent char"),
+  MMTuple(
+MMString("Simple C++ TBAA")),
+  MConstInt(0, 64)
+);
+
+
+TEST(TBAAMetadataTest, BasicTypes) {
+  const char TestProgram[] = R"**(
+void func(char *CP, short *SP, int *IP, long long *LP, void **VPP,
+  int **IPP) {
+  *CP = 4;
+  *SP = 11;
+  *IP = 601;
+  *LP = 604;
+  *VPP = CP;
+  *IPP = IP;
+}
+  )**";
+
+  TestCompiler Compiler;
+  Compiler.compiler.getLangOpts().C1

[PATCH] D41237: [Frontend] Handle skipped bodies in template instantiations

2017-12-20 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff accepted this revision.
sepavloff added a comment.
This revision is now accepted and ready to land.

LGTM.

Thanks!


Repository:
  rC Clang

https://reviews.llvm.org/D41237



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


[PATCH] D24933: Enable configuration files in clang

2017-12-21 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 127911.
sepavloff marked 2 inline comments as done.
sepavloff added a comment.

Small corrections to the patch

- Avoid quick return in the case of error, it may cause fails of clang tools.
- Fixed typo.


Repository:
  rC Clang

https://reviews.llvm.org/D24933

Files:
  docs/UsersManual.rst
  include/clang/Basic/DiagnosticDriverKinds.td
  include/clang/Config/config.h.cmake
  include/clang/Driver/Driver.h
  include/clang/Driver/Options.td
  lib/Driver/Driver.cpp
  test/Driver/Inputs/config-1.cfg
  test/Driver/Inputs/config-2.cfg
  test/Driver/Inputs/config-2a.cfg
  test/Driver/Inputs/config-3.cfg
  test/Driver/Inputs/config-4.cfg
  test/Driver/Inputs/config-5.cfg
  test/Driver/Inputs/config-6.cfg
  test/Driver/Inputs/config/config-4.cfg
  test/Driver/Inputs/config/i386-qqq.cfg
  test/Driver/Inputs/config/i386-qqq3.cfg
  test/Driver/Inputs/config/x86_64-qqq.cfg
  test/Driver/Inputs/config/x86_64-qqq2.cfg
  test/Driver/Inputs/config/x86_64.cfg
  test/Driver/Inputs/config2/config-4.cfg
  test/Driver/Inputs/config2/i386.cfg
  test/Driver/config-file-errs.c
  test/Driver/config-file.c
  test/Driver/config-file2.c
  test/Driver/config-file3.c

Index: test/Driver/config-file3.c
===
--- /dev/null
+++ test/Driver/config-file3.c
@@ -0,0 +1,98 @@
+// REQUIRES: shell
+// REQUIRES: x86-registered-target
+
+//--- If config file is specified by relative path (workdir/cfg-s2), it is searched for by that path.
+//
+// RUN: mkdir -p %T/workdir
+// RUN: echo "@subdir/cfg-s2" > %T/workdir/cfg-1
+// RUN: mkdir -p %T/workdir/subdir
+// RUN: echo "-Wundefined-var-template" > %T/workdir/subdir/cfg-s2
+//
+// RUN: ( cd %T && %clang --config workdir/cfg-1 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-REL )
+//
+// CHECK-REL: Configuration file: {{.*}}/workdir/cfg-1
+// CHECK-REL: -Wundefined-var-template
+
+
+//--- Invocation qqq-clang-g++ tries to find config file qqq-clang-g++.cfg first.
+//
+// RUN: mkdir -p %T/testdmode
+// RUN: [ ! -s %T/testdmode/qqq-clang-g++ ] || rm %T/testdmode/qqq-clang-g++
+// RUN: ln -s %clang %T/testdmode/qqq-clang-g++
+// RUN: echo "-Wundefined-func-template" > %T/testdmode/qqq-clang-g++.cfg
+// RUN: echo "-Werror" > %T/testdmode/qqq.cfg
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir= -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix FULL-NAME
+//
+// FULL-NAME: Configuration file: {{.*}}/testdmode/qqq-clang-g++.cfg
+// FULL-NAME: -Wundefined-func-template
+// FULL-NAME-NOT: -Werror
+//
+//--- File specified by --config overrides config inferred from clang executable.
+//
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --config i386-qqq -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-EXPLICIT
+//
+// CHECK-EXPLICIT: Configuration file: {{.*}}/Inputs/config/i386-qqq.cfg
+//
+//--- Invocation qqq-clang-g++ tries to find config file qqq.cfg if qqq-clang-g++.cfg is not found.
+//
+// RUN: rm %T/testdmode/qqq-clang-g++.cfg
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir= -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix SHORT-NAME
+//
+// SHORT-NAME: Configuration file: {{.*}}/testdmode/qqq.cfg
+// SHORT-NAME: -Werror
+// SHORT-NAME-NOT: -Wundefined-func-template
+
+
+//--- Config files are searched for in binary directory as well.
+//
+// RUN: mkdir -p %T/testbin
+// RUN: [ ! -s %T/testbin/clang ] || rm %T/testbin/clang
+// RUN: ln -s %clang %T/testbin/clang
+// RUN: echo "-Werror" > %T/testbin/aaa.cfg
+// RUN: %T/testbin/clang --config-system-dir= --config-user-dir= --config aaa.cfg -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-BIN
+//
+// CHECK-BIN: Configuration file: {{.*}}/testbin/aaa.cfg
+// CHECK-BIN: -Werror
+
+
+//--- If command line contains options that change triple (for instance, -m32), clang tries
+//reloading config file.
+
+//--- When reloading config file, x86_64-clang-g++ tries to find config i386-clang-g++.cfg first.
+//
+// RUN: mkdir -p %T/testreload
+// RUN: [ ! -s %T/testreload/x86_64-clang-g++ ] || rm %T/testreload/x86_64-clang-g++
+// RUN: ln -s %clang %T/testreload/x86_64-clang-g++
+// RUN: echo "-Wundefined-func-template" > %T/testreload/i386-clang-g++.cfg
+// RUN: echo "-Werror" > %T/testreload/i386.cfg
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir= --config-user-dir= -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD
+//
+// CHECK-RELOAD: Configuration file: {{.*}}/testreload/i386-clang-g++.cfg
+// CHECK-RELOAD: -Wundefined-func-template
+// CHECK-RELOAD-NOT: -Werror
+
+//--- If config file is specified by --config and its name does not start with architecture, it is used without reloading.
+//
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir=%S/Inputs --config-user-dir= --config config-3 -c -m32 -no-canonical-prefixes %

[PATCH] D41433: Unit tests for TBAA metadata generation.

2017-12-22 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL321360: Unit tests for TBAA metadata generation. (authored 
by sepavloff, committed by ).

Repository:
  rL LLVM

https://reviews.llvm.org/D41433

Files:
  cfe/trunk/unittests/CodeGen/CMakeLists.txt
  cfe/trunk/unittests/CodeGen/IRMatchers.h
  cfe/trunk/unittests/CodeGen/TBAAMetadataTest.cpp

Index: cfe/trunk/unittests/CodeGen/CMakeLists.txt
===
--- cfe/trunk/unittests/CodeGen/CMakeLists.txt
+++ cfe/trunk/unittests/CodeGen/CMakeLists.txt
@@ -7,6 +7,7 @@
   BufferSourceTest.cpp
   CodeGenExternalTest.cpp
   IncrementalProcessingTest.cpp
+  TBAAMetadataTest.cpp
   )
 
 target_link_libraries(ClangCodeGenTests
Index: cfe/trunk/unittests/CodeGen/TBAAMetadataTest.cpp
===
--- cfe/trunk/unittests/CodeGen/TBAAMetadataTest.cpp
+++ cfe/trunk/unittests/CodeGen/TBAAMetadataTest.cpp
@@ -0,0 +1,1299 @@
+//=== unittests/CodeGen/TBAAMetadataTest.cpp - Checks metadata generation -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "IRMatchers.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Parse/ParseAST.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+#include 
+
+using namespace llvm;
+
+namespace {
+
+struct TestCompiler {
+  LLVMContext Context;
+  clang::CompilerInstance compiler;
+  clang::CodeGenerator *CG = nullptr;
+  llvm::Module *M = nullptr;
+  unsigned PtrSize = 0;
+
+  void init(const char *TestProgram) {
+compiler.createDiagnostics();
+compiler.getCodeGenOpts().StructPathTBAA = 1;
+compiler.getCodeGenOpts().OptimizationLevel = 1;
+
+std::string TrStr = llvm::Triple::normalize(llvm::sys::getProcessTriple());
+llvm::Triple Tr(TrStr);
+Tr.setOS(Triple::Linux);
+Tr.setVendor(Triple::VendorType::UnknownVendor);
+Tr.setEnvironment(Triple::EnvironmentType::UnknownEnvironment);
+compiler.getTargetOpts().Triple = Tr.getTriple();
+compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
+compiler.getDiagnostics(),
+std::make_shared(compiler.getTargetOpts(;
+
+const clang::TargetInfo &TInfo = compiler.getTarget();
+PtrSize = TInfo.getPointerWidth(0) / 8;
+
+compiler.createFileManager();
+compiler.createSourceManager(compiler.getFileManager());
+compiler.createPreprocessor(clang::TU_Prefix);
+
+compiler.createASTContext();
+
+CG = CreateLLVMCodeGen(
+compiler.getDiagnostics(),
+"main-module",
+compiler.getHeaderSearchOpts(),
+compiler.getPreprocessorOpts(),
+compiler.getCodeGenOpts(),
+Context);
+compiler.setASTConsumer(std::unique_ptr(CG));
+
+compiler.createSema(clang::TU_Prefix, nullptr);
+
+clang::SourceManager &sm = compiler.getSourceManager();
+sm.setMainFileID(sm.createFileID(
+llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
+  }
+
+  const BasicBlock *compile() {
+clang::ParseAST(compiler.getSema(), false, false);
+M = CG->GetModule();
+
+// Do not expect more than one function definition.
+auto FuncPtr = M->begin();
+for (; FuncPtr != M->end(); ++FuncPtr)
+  if (!FuncPtr->isDeclaration())
+break;
+assert(FuncPtr != M->end());
+const llvm::Function &Func = *FuncPtr;
+++FuncPtr;
+for (; FuncPtr != M->end(); ++FuncPtr)
+  if (!FuncPtr->isDeclaration())
+break;
+assert(FuncPtr == M->end());
+
+// The function must consist of single basic block.
+auto BBPtr = Func.begin();
+assert(Func.begin() != Func.end());
+const BasicBlock &BB = *BBPtr;
+++BBPtr;
+assert(BBPtr == Func.end());
+
+return &BB;
+  }
+};
+
+
+auto OmnipotentCharC = MMTuple(
+  MMString("omnipotent char"),
+  MMTuple(
+MMString("Simple C/C++ TBAA")),
+  MConstInt(0, 64)
+);
+
+
+auto OmnipotentCharCXX = MMTuple(
+  MMString("omnipotent char"),
+  MMTuple(
+MMString("Simple C++ TBAA")),
+  MConstInt(0, 64)
+);
+
+
+TEST(TBAAMetadataTest, BasicTypes) {
+  const char TestProgram[] = R"**(
+void func(char *CP, short *SP, int *IP, long long *LP, void **VPP,
+  int **IPP) {
+  *CP = 4;
+  *SP = 11;
+  *IP = 601;
+  *LP = 604;
+  *VPP = CP;
+  *IPP = IP;
+}
+  )**";
+
+  TestCompiler Compiler;
+  Compiler.compiler.getLangOpts().C11 = 1;
+  Compiler.init(TestProgram);
+  const BasicBlock *BB = Compiler.compile();
+
+  cons

[PATCH] D41492: [Frontend] Correctly handle instantiating ctors with skipped bodies

2017-12-25 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff accepted this revision.
sepavloff added a comment.
This revision is now accepted and ready to land.

LGTM.

Thanks!


Repository:
  rC Clang

https://reviews.llvm.org/D41492



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


[PATCH] D41179: [Sema] Diagnose template specializations with C linkage

2017-12-27 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

In https://reviews.llvm.org/D41179#964526, @faisalv wrote:

> In https://reviews.llvm.org/D41179#964522, @miyuki wrote:
>
> > In https://reviews.llvm.org/D41179#957992, @sepavloff wrote:
> >
> > >   Classes do not have language linkage according to 10.5p1, just as 
> > > templates, so this code is valid.
> > >  
> > >   It looks like defining templates inside extern "C" blocks is OK.
> >
> >
> > Currently both Clang and GCC diagnose class templates declared inside an 
> > 'extern "C"' block. I'm not sure how to proceed about this.
>
>
> Given that Clause 17 p6 specifically uses 'shall' to call out templates - i 
> believe the implementation is expected to diagnose this.  10.5p1 (or is there 
> another mention in the standard?) does not explicitly call out 'classes' as 
> not having c language linkage - so implementations can get away not 
> diagnosing this - and perhaps even allow classes to have language linkage on 
> certain implementations?? (at least that's my squinty interpretation)


This is a strange clause. The language linkage describes cases when an entity 
defined in one TU is identical to another entity in another TU implemented in 
different language. As templates have no meaning outside C++, so they merely 
cannot have C linkage.

I guess the statement about C linkage in 17p6 is a remnant of those times when 
template were allowed to have `export` specifier. In that case templates would 
have external representation and in principle could be used in non C++ 
compilation.

Maybe @rsmith could clarify this point?


https://reviews.llvm.org/D41179



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


[PATCH] D24933: Enable configuration files in clang

2017-12-30 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL321587: Enable configuration files in clang (authored by 
sepavloff, committed by ).

Repository:
  rL LLVM

https://reviews.llvm.org/D24933

Files:
  cfe/trunk/docs/UsersManual.rst
  cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
  cfe/trunk/include/clang/Config/config.h.cmake
  cfe/trunk/include/clang/Driver/Driver.h
  cfe/trunk/include/clang/Driver/Options.td
  cfe/trunk/lib/Driver/Driver.cpp
  cfe/trunk/test/Driver/Inputs/config-1.cfg
  cfe/trunk/test/Driver/Inputs/config-2.cfg
  cfe/trunk/test/Driver/Inputs/config-2a.cfg
  cfe/trunk/test/Driver/Inputs/config-3.cfg
  cfe/trunk/test/Driver/Inputs/config-4.cfg
  cfe/trunk/test/Driver/Inputs/config-5.cfg
  cfe/trunk/test/Driver/Inputs/config-6.cfg
  cfe/trunk/test/Driver/Inputs/config/config-4.cfg
  cfe/trunk/test/Driver/Inputs/config/i386-qqq.cfg
  cfe/trunk/test/Driver/Inputs/config/i386-qqq3.cfg
  cfe/trunk/test/Driver/Inputs/config/x86_64-qqq.cfg
  cfe/trunk/test/Driver/Inputs/config/x86_64-qqq2.cfg
  cfe/trunk/test/Driver/Inputs/config/x86_64.cfg
  cfe/trunk/test/Driver/Inputs/config2/config-4.cfg
  cfe/trunk/test/Driver/Inputs/config2/i386.cfg
  cfe/trunk/test/Driver/config-file-errs.c
  cfe/trunk/test/Driver/config-file.c
  cfe/trunk/test/Driver/config-file2.c
  cfe/trunk/test/Driver/config-file3.c

Index: cfe/trunk/lib/Driver/Driver.cpp
===
--- cfe/trunk/lib/Driver/Driver.cpp
+++ cfe/trunk/lib/Driver/Driver.cpp
@@ -62,14 +62,16 @@
 #include "llvm/Option/OptSpecifier.h"
 #include "llvm/Option/OptTable.h"
 #include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/StringSaver.h"
 #include 
 #include 
 #include 
@@ -92,7 +94,8 @@
   CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr),
   CCCPrintBindings(false), CCPrintHeaders(false), CCLogDiagnostics(false),
   CCGenDiagnostics(false), DefaultTargetTriple(DefaultTargetTriple),
-  CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true),
+  CCCGenericGCCName(""), Saver(Alloc),
+  CheckInputsExist(true), CCCUsePCH(true),
   GenReproducer(false), SuppressMissingInputWarning(false) {
 
   // Provide a sane fallback if no VFS is specified.
@@ -103,6 +106,13 @@
   Dir = llvm::sys::path::parent_path(ClangExecutable);
   InstalledDir = Dir; // Provide a sensible default installed dir.
 
+#if defined(CLANG_CONFIG_FILE_SYSTEM_DIR)
+  SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR;
+#endif
+#if defined(CLANG_CONFIG_FILE_USER_DIR)
+  UserConfigDir = CLANG_CONFIG_FILE_USER_DIR;
+#endif
+
   // Compute the path to the resource directory.
   StringRef ClangResourceDir(CLANG_RESOURCE_DIR);
   SmallString<128> P(Dir);
@@ -600,6 +610,216 @@
   //
 }
 
+/// Looks the given directories for the specified file.
+///
+/// \param[out] FilePath File path, if the file was found.
+/// \param[in]  Dirs Directories used for the search.
+/// \param[in]  FileName Name of the file to search for.
+/// \return True if file was found.
+///
+/// Looks for file specified by FileName sequentially in directories specified
+/// by Dirs.
+///
+static bool searchForFile(SmallVectorImpl &FilePath,
+  ArrayRef Dirs,
+  StringRef FileName) {
+  SmallString<128> WPath;
+  for (const StringRef &Dir : Dirs) {
+if (Dir.empty())
+  continue;
+WPath.clear();
+llvm::sys::path::append(WPath, Dir, FileName);
+llvm::sys::path::native(WPath);
+if (llvm::sys::fs::is_regular_file(WPath)) {
+  FilePath = std::move(WPath);
+  return true;
+}
+  }
+  return false;
+}
+
+bool Driver::readConfigFile(StringRef FileName) {
+  // Try reading the given file.
+  SmallVector NewCfgArgs;
+  if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs)) {
+Diag(diag::err_drv_cannot_read_config_file) << FileName;
+return true;
+  }
+
+  // Read options from config file.
+  llvm::SmallString<128> CfgFileName(FileName);
+  llvm::sys::path::native(CfgFileName);
+  ConfigFile = CfgFileName.str();
+  bool ContainErrors;
+  CfgOptions = llvm::make_unique(
+  ParseArgStrings(NewCfgArgs, ContainErrors));
+  if (ContainErrors) {
+CfgOptions.reset();
+return true;
+  }
+
+  if (CfgOptions->hasArg(options::OPT_config)) {
+CfgOptions.reset();
+Diag(diag::err_drv_nested_config_file);
+return true;
+  }
+
+  // Claim all arguments that come from a configuration file so that the driver
+  // does not warn on any that is unused.
+  for (Arg *A : *CfgOptions)
+A->claim();
+  return false;
+}
+
+bool Driver::loadConfigFile() {

[PATCH] D43805: Optionally use nameless IR types

2018-02-26 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: rsmith, rjmccall.

Type in the LLVM IR may have names but only for the purpose of human
readability (see discussions in https://reviews.llvm.org/D40567,
http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20171127/210816.html
and http://lists.llvm.org/pipermail/llvm-dev/2017-December/119585.html).
In the case when the resulting IR is not proposed for reading, for
instance, when compilation produces machine code, the type names are waste
of memory. In some cases, when types are nested in other types, the memory
expenses may be really large.

This change implements new clang option, '--ir-type-names=', which controls
if IR types should be given human readable names. The option may have
values 'use' or 'none', which turn names on or off correspondently. If no such
option was specified, compiler assign names when output may be read by a
human, namely when IR is saved beyond compilation or in debug builds.


Repository:
  rC Clang

https://reviews.llvm.org/D43805

Files:
  include/clang/Driver/Options.td
  include/clang/Frontend/CodeGenOptions.def
  include/clang/Frontend/CodeGenOptions.h
  lib/CodeGen/CodeGenAction.cpp
  lib/CodeGen/CodeGenTypes.cpp
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenCXX/pr29160.cpp
  test/CodeGenCXX/type-names.cpp

Index: test/CodeGenCXX/type-names.cpp
===
--- /dev/null
+++ test/CodeGenCXX/type-names.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm --ir-type-names=use -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm --ir-type-names=none -o - %s | FileCheck %s --check-prefix=UNNAMED
+
+struct C1 {
+  int a;
+  int *b;
+};
+
+C1 var_C1_a;
+C1 var_C1_b[10];
+C1 *var_C1_c;
+int (*var_C1_d)(const C1 &);
+
+struct C1A {
+  int a;
+  int *b;
+};
+
+C1A var_C1A_a;
+
+template struct C2 {
+  C1 a;
+  T b;
+  struct Inner {
+  };
+};
+
+C2 var_C2_a;
+C2 var_C2_b;
+C2::Inner var_C2_c;
+
+struct C3 {
+  double a;
+  struct C4 {
+int a;
+float b;
+  };
+};
+
+C3::C4 var_c4;
+
+namespace {
+struct C5 {
+  int *a;
+};
+}
+
+C5 var_C5_a;
+void *var_C5_b = &var_C5_a;
+
+// CHECK: %struct.C1 = type { i32, i32* }
+// CHECK: %struct.C1A = type { i32, i32* }
+// CHECK: %struct.C2 = type { %struct.C1, i16 }
+// CHECK: %struct.C2.0 = type { %struct.C1, i64 }
+// CHECK: %"struct.C2::Inner" = type { i8 }
+// CHECK: %"struct.C3::C4" = type { i32, float }
+// CHECK: %"struct.(anonymous namespace)::C5" = type { i32* }
+
+// UNNAMED: %0 = type { i32, i32* }
+// UNNAMED: %1 = type { i32, i32* }
+// UNNAMED: %2 = type { %0, i16 }
+// UNNAMED: %3 = type { %0, i64 }
+// UNNAMED: %4 = type { i8 }
+// UNNAMED: %5 = type { i32, float }
+// UNNAMED: %6 = type { i32* }
Index: test/CodeGenCXX/pr29160.cpp
===
--- test/CodeGenCXX/pr29160.cpp
+++ test/CodeGenCXX/pr29160.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm
+// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu -DNAMELESS --ir-type-names=none %s -o /dev/null -S -emit-llvm
 //
 // This test's failure mode is running ~forever. (For some value of "forever"
 // that's greater than 25 minutes on my machine)
@@ -8,6 +9,7 @@
   template 
   static void ignore() {}
   Foo() { ignore(); }
+  struct ABC {};
 };
 
 struct Base {
@@ -39,3 +41,9 @@
 STAMP(Q, P);
 
 int main() { Q q; }
+
+#ifdef NAMELESS
+// Without '--ir-type-names=none' compiler tries to create name for Q::ABC,
+// which is really huge, so compilation never ends.
+Q::ABC var;
+#endif
Index: lib/Frontend/CompilerInvocation.cpp
===
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -804,6 +804,19 @@
 }
   }
 
+  if (Arg *A = Args.getLastArg(OPT_ir_type_names_EQ)) {
+StringRef Name = A->getValue();
+auto Info = llvm::StringSwitch(Name)
+.Case("none", CodeGenOptions::IRNameKind::None)
+.Case("use", CodeGenOptions::IRNameKind::Use)
+.Default(CodeGenOptions::IRNameKind::Unspecified);
+if (Info == CodeGenOptions::IRNameKind::Unspecified) {
+  Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+  Success = false;
+} else
+  Opts.setIRTypeNames(Info);
+  }
+
   Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type);
   Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
   Opts.InstrumentFunctionsAfterInlining =
Index: lib/Driver/ToolChains/Clang.cpp
===
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -3279,6 +3279,8 @@
   if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO())
 CmdArgs.push_back("-fembed-bitcode=marker");
 
+  Args.AddLastArg(CmdArgs, options

[PATCH] D40567: Always show template parameters in IR type names

2018-02-26 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff abandoned this revision.
sepavloff added a comment.

The feedback here, in https://reviews.llvm.org/D40508 and in the mail list 
(http://lists.llvm.org/pipermail/llvm-dev/2017-December/119585.html) 
demonstrates that this is a wrong direction.
Part of this patch is used in https://reviews.llvm.org/D43805, which implements 
in some sense an opposite approach, - using nameless llvm types.


Repository:
  rC Clang

https://reviews.llvm.org/D40567



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


[PATCH] D40508: Replace long type names in IR with hashes

2018-02-26 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff abandoned this revision.
sepavloff added a comment.

Using llvm type names is considered a wrong direction.


https://reviews.llvm.org/D40508



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


[PATCH] D43805: Optionally use nameless IR types

2018-02-27 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 136087.
sepavloff added a comment.

Updated patch

- command line option was renamed to `-fir-type-names=`,
- this option is not hidden, as most options in `-f` namespace,
- new value, `auto` was added to possible values of this option.


Repository:
  rC Clang

https://reviews.llvm.org/D43805

Files:
  include/clang/Driver/Options.td
  include/clang/Frontend/CodeGenOptions.def
  include/clang/Frontend/CodeGenOptions.h
  lib/CodeGen/CodeGenAction.cpp
  lib/CodeGen/CodeGenTypes.cpp
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenCXX/pr29160.cpp
  test/CodeGenCXX/type-names.cpp

Index: test/CodeGenCXX/type-names.cpp
===
--- /dev/null
+++ test/CodeGenCXX/type-names.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -fir-type-names=use -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -fir-type-names=none -o - %s | FileCheck %s --check-prefix=UNNAMED
+
+struct C1 {
+  int a;
+  int *b;
+};
+
+C1 var_C1_a;
+C1 var_C1_b[10];
+C1 *var_C1_c;
+int (*var_C1_d)(const C1 &);
+
+struct C1A {
+  int a;
+  int *b;
+};
+
+C1A var_C1A_a;
+
+template struct C2 {
+  C1 a;
+  T b;
+  struct Inner {
+  };
+};
+
+C2 var_C2_a;
+C2 var_C2_b;
+C2::Inner var_C2_c;
+
+struct C3 {
+  double a;
+  struct C4 {
+int a;
+float b;
+  };
+};
+
+C3::C4 var_c4;
+
+namespace {
+struct C5 {
+  int *a;
+};
+}
+
+C5 var_C5_a;
+void *var_C5_b = &var_C5_a;
+
+// CHECK: %struct.C1 = type { i32, i32* }
+// CHECK: %struct.C1A = type { i32, i32* }
+// CHECK: %struct.C2 = type { %struct.C1, i16 }
+// CHECK: %struct.C2.0 = type { %struct.C1, i64 }
+// CHECK: %"struct.C2::Inner" = type { i8 }
+// CHECK: %"struct.C3::C4" = type { i32, float }
+// CHECK: %"struct.(anonymous namespace)::C5" = type { i32* }
+
+// UNNAMED: %0 = type { i32, i32* }
+// UNNAMED: %1 = type { i32, i32* }
+// UNNAMED: %2 = type { %0, i16 }
+// UNNAMED: %3 = type { %0, i64 }
+// UNNAMED: %4 = type { i8 }
+// UNNAMED: %5 = type { i32, float }
+// UNNAMED: %6 = type { i32* }
Index: test/CodeGenCXX/pr29160.cpp
===
--- test/CodeGenCXX/pr29160.cpp
+++ test/CodeGenCXX/pr29160.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm
+// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu -DNAMELESS -fir-type-names=none %s -o /dev/null -S -emit-llvm
 //
 // This test's failure mode is running ~forever. (For some value of "forever"
 // that's greater than 25 minutes on my machine)
@@ -8,6 +9,7 @@
   template 
   static void ignore() {}
   Foo() { ignore(); }
+  struct ABC {};
 };
 
 struct Base {
@@ -39,3 +41,9 @@
 STAMP(Q, P);
 
 int main() { Q q; }
+
+#ifdef NAMELESS
+// Without '-fir-type-names=none' compiler tries to create name for Q::ABC,
+// which is really huge, so compilation never ends.
+Q::ABC var;
+#endif
Index: lib/Frontend/CompilerInvocation.cpp
===
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -804,6 +804,20 @@
 }
   }
 
+  if (Arg *A = Args.getLastArg(OPT_fir_type_names_EQ)) {
+StringRef Name = A->getValue();
+auto Info = llvm::StringSwitch(Name)
+.Case("auto", CodeGenOptions::IRNames_Auto)
+.Case("none", CodeGenOptions::IRNames_None)
+.Case("use", CodeGenOptions::IRNames_Use)
+.Default(-1);
+if (Info == -1) {
+  Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+  Success = false;
+} else
+  Opts.setIRTypeNames(static_cast(Info));
+  }
+
   Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type);
   Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
   Opts.InstrumentFunctionsAfterInlining =
Index: lib/Driver/ToolChains/Clang.cpp
===
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -3279,6 +3279,8 @@
   if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO())
 CmdArgs.push_back("-fembed-bitcode=marker");
 
+  Args.AddLastArg(CmdArgs, options::OPT_fir_type_names_EQ);
+
   // We normally speed up the clang process a bit by skipping destructors at
   // exit, but when we're generating diagnostics we can rely on some of the
   // cleanup.
Index: lib/CodeGen/CodeGenTypes.cpp
===
--- lib/CodeGen/CodeGenTypes.cpp
+++ lib/CodeGen/CodeGenTypes.cpp
@@ -51,10 +51,13 @@
 void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
  llvm::StructType *Ty,
  StringRef suffix) {
+  if (getCodeGenOpts().getIRTypeNames() == CodeGenOptions::IRNames_None)
+return;
+
   SmallString<256> TypeName;
   llvm::raw_svector_ostream OS(

[PATCH] D43805: Optionally use nameless IR types

2018-02-27 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked an inline comment as done.
sepavloff added inline comments.



Comment at: include/clang/Driver/Options.td:1735
+  HelpText<"Whether to use IR type names (option: none, use)">,
+  Values<"none,use">;
 def relocatable_pch : Flag<["-", "--"], "relocatable-pch">, Flags<[CC1Option]>,

rjmccall wrote:
> This is an unusual spelling for the option in a number of ways:
>   - We generally don't use `--` options; I think all the ones we have are 
> strictly for legacy support.
>   - A lot of similar options are in the `-f` or `-m` namespaces, although 
> that's not as consistent and we could reasonably make this an exception.
>   - `-foo=bar` options are generally used for options that are expected to 
> take a variety of different values; this seems basically boolean.  Are you 
> expecting future growth here?
The option is in fact a three-state one, the third 'value' is absence of the 
option. In this case the option value is calculated from the type of action 
(produce ll file or not) and from the type of build (in debug builds types are 
named by default). To avoid misunderstanding I added new value, 'auto' for this 
purpose.

The option was renamed to `-fir-type-names=` and it is not hidden anymore.


Repository:
  rC Clang

https://reviews.llvm.org/D43805



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


[PATCH] D30170: Function definition may have uninstantiated body

2018-02-28 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

The issue is still observed in trunk. Other compilers process the tests 
correctly (checked using https://godbolt.org/). For instance, the code:

  template struct C20 {
  friend void func_20() {} // expected-note{{previous definition is here}}
  };
  C20 c20i;
  void func_20() {} // expected-error{{redefinition of 'func_20'}}

is rejected by gcc 7.3:

  : In function 'void func_20()':
  :5:6: error: redefinition of 'void func_20()'
   void func_20() {} // expected-error{{redefinition of 'func_20'}}
^~~
  :2:13: note: 'void func_20()' previously declared here
   friend void func_20() {} // expected-note{{previous definition is here}}
   ^~~
  Compiler returned: 1

by ICC 18:

  (5): error: function "func_20" has already been defined
void func_20() {} // expected-error{{redefinition of 'func_20'}}
 ^
  compilation aborted for  (code 2)
  Compiler returned: 2

and by MSVC 19 2017:

  (5): error C2084: function 'void C20::func_20(void)' already has 
a body
  (2): note: see previous definition of 'func_20'
  Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x64
  Copyright (C) Microsoft Corporation.  All rights reserved.
  Compiler returned: 2


https://reviews.llvm.org/D30170



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


[PATCH] D30170: Function definition may have uninstantiated body

2018-02-28 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL326419: Function definition may have uninstantiated body 
(authored by sepavloff, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D30170?vs=115534&id=136466#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D30170

Files:
  cfe/trunk/include/clang/AST/Decl.h
  cfe/trunk/lib/Sema/SemaDecl.cpp
  cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
  cfe/trunk/test/SemaCXX/friend2.cpp

Index: cfe/trunk/include/clang/AST/Decl.h
===
--- cfe/trunk/include/clang/AST/Decl.h
+++ cfe/trunk/include/clang/AST/Decl.h
@@ -1925,11 +1925,25 @@
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
-  /// \brief Returns true if the function has a body (definition). The
-  /// function body might be in any of the (re-)declarations of this
-  /// function. The variant that accepts a FunctionDecl pointer will
-  /// set that function declaration to the actual declaration
-  /// containing the body (if there is one).
+  // Function definitions.
+  //
+  // A function declaration may be:
+  // - a non defining declaration,
+  // - a definition. A function may be defined because:
+  //   - it has a body, or will have it in the case of late parsing.
+  //   - it has an uninstantiated body. The body does not exist because the
+  // function is not used yet, but the declaration is considered a
+  // definition and does not allow other definition of this function.
+  //   - it does not have a user specified body, but it does not allow
+  // redefinition, because it is deleted/defaulted or is defined through
+  // some other mechanism (alias, ifunc).
+
+  /// Returns true if the function has a body.
+  ///
+  /// The function body might be in any of the (re-)declarations of this
+  /// function. The variant that accepts a FunctionDecl pointer will set that
+  /// function declaration to the actual declaration containing the body (if
+  /// there is one).
   bool hasBody(const FunctionDecl *&Definition) const;
 
   bool hasBody() const override {
@@ -1941,9 +1955,11 @@
   /// specific codegen.
   bool hasTrivialBody() const;
 
-  /// Returns true if the function is defined at all, including a deleted
-  /// definition. Except for the behavior when the function is deleted, behaves
-  /// like hasBody.
+  /// Returns true if the function has a definition that does not need to be
+  /// instantiated.
+  ///
+  /// The variant that accepts a FunctionDecl pointer will set that function
+  /// declaration to the declaration that is a definition (if there is one).
   bool isDefined(const FunctionDecl *&Definition) const;
 
   virtual bool isDefined() const {
@@ -1985,8 +2001,7 @@
IsLateTemplateParsed || WillHaveBody || hasDefiningAttr();
   }
 
-  /// Returns whether this specific declaration of the function has a body -
-  /// that is, if it is a non-deleted definition.
+  /// Returns whether this specific declaration of the function has a body.
   bool doesThisDeclarationHaveABody() const {
 return Body || IsLateTemplateParsed;
   }
Index: cfe/trunk/test/SemaCXX/friend2.cpp
===
--- cfe/trunk/test/SemaCXX/friend2.cpp
+++ cfe/trunk/test/SemaCXX/friend2.cpp
@@ -101,6 +101,34 @@
   friend void func_12(int x = 0);  // expected-error{{friend declaration specifying a default argument must be the only declaration}}
 };
 
+// Friend function with uninstantiated body is still a definition.
+
+template struct C20 {
+  friend void func_20() {} // expected-note{{previous definition is here}}
+};
+C20 c20i;
+void func_20() {} // expected-error{{redefinition of 'func_20'}}
+
+template struct C21a {
+  friend void func_21() {} // expected-note{{previous definition is here}}
+};
+template struct C21b {
+  friend void func_21() {} // expected-error{{redefinition of 'func_21'}}
+};
+C21a c21ai;
+C21b c21bi; // expected-note{{in instantiation of template class 'C21b' requested here}}
+
+template struct C22a {
+  friend void func_22() {} // expected-note{{previous definition is here}}
+};
+template struct C22b {
+  friend void func_22();
+};
+C22a c22ai;
+C22b c22bi;
+void func_22() {} // expected-error{{redefinition of 'func_22'}}
+
+
 
 namespace pr22307 {
 
Index: cfe/trunk/lib/Sema/SemaDecl.cpp
===
--- cfe/trunk/lib/Sema/SemaDecl.cpp
+++ cfe/trunk/lib/Sema/SemaDecl.cpp
@@ -12283,9 +12283,36 @@
const FunctionDecl *EffectiveDefinition,
SkipBodyInfo *SkipBody) {
   const FunctionDecl *Definition = EffectiveDefinition;
+  if (!Definition && !FD->isDefined(Definition) && !FD->isCXXClassMember()) {
+// If this is a friend function defined in a class template, it does not
+// have a body until it is u

[PATCH] D30170: Function definition may have uninstantiated body

2018-02-28 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked 3 inline comments as done.
sepavloff added a comment.

Thank you!




Comment at: lib/Sema/SemaDecl.cpp:11995-12006
+for (auto I : FD->redecls()) {
+  if (I != FD && !I->isInvalidDecl() &&
+  I->getFriendObjectKind() != Decl::FOK_None) {
+if (FunctionDecl *Original = I->getInstantiatedFromMemberFunction()) {
+  if (Original->isThisDeclarationADefinition()) {
+Definition = I;
+break;

rsmith wrote:
> We should include a comment here explaining why we need to do this (that is, 
> why this doesn't just fall out from the normal `isDefined` check). You can 
> just quote C++ [temp.inst]p2:
> 
> > For the purpose of determining whether an instantiated redeclaration is 
> > valid according to [basic.def.odr] and [class.mem], a declaration that 
> > corresponds to a definition in the template is considered to be a 
> > definition.
Thank you for the reference.


Repository:
  rL LLVM

https://reviews.llvm.org/D30170



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


[PATCH] D43805: Optionally use nameless IR types

2018-03-06 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked an inline comment as done.
sepavloff added a comment.

In https://reviews.llvm.org/D43805#1029455, @pcc wrote:

> Why is this a driver flag? This seems like it ought to be a cc1-only flag to 
> me.


Yous are right, this is more like development option. But having the driver 
flag allows using compiler in builds with either option.
The option was hidden, probably it should be make hidden again.
If the backend will be changed so that it will not depend on IR type names, the 
default mode can be set to nameless types and the option can become -cc1 only.


Repository:
  rC Clang

https://reviews.llvm.org/D43805



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


[PATCH] D43805: Optionally use nameless IR types

2018-03-06 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added inline comments.



Comment at: include/clang/Driver/Options.td:644
+  HelpText<"Whether to use IR type names (option: auto, none, use)">,
+  Values<"auto,none,use">;
+

rsmith wrote:
> Having "none" and "use" as values for the same option seems like a category 
> error. always / never / auto would make some sense, though.
Indeed. Will change it.


Repository:
  rC Clang

https://reviews.llvm.org/D43805



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


[PATCH] D43805: Optionally use nameless IR types

2018-03-06 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

In https://reviews.llvm.org/D43805#1029479, @pcc wrote:

> > If the backend will be changed so that it will not depend on IR type names
>
> Are you referring to https://reviews.llvm.org/D43199? If so it seems to me 
> that this should be a cc1 flag that defaults to whether `-flto=thin` is 
> passed. In any case it seems like a bad idea to deliberately generate 
> different code depending on whether we were compiled with NDEBUG.


No, I try to implement alternative approach, to solve the problem targeted in 
https://reviews.llvm.org/D40508. If  IR type names are only for human 
readability, than using them in opaque type resolution does not look 
reasonable. Probably, more correct way is to make type merge only as a side 
effect of merge of other entities, which may have "real" names, that is 
functions and variables.


Repository:
  rC Clang

https://reviews.llvm.org/D43805



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


[PATCH] D43805: Optionally use nameless IR types

2018-03-07 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 137336.
sepavloff added a comment.

Use more consistent option names


Repository:
  rC Clang

https://reviews.llvm.org/D43805

Files:
  include/clang/Driver/Options.td
  include/clang/Frontend/CodeGenOptions.def
  include/clang/Frontend/CodeGenOptions.h
  lib/CodeGen/CodeGenAction.cpp
  lib/CodeGen/CodeGenTypes.cpp
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenCXX/pr29160.cpp
  test/CodeGenCXX/type-names.cpp

Index: test/CodeGenCXX/type-names.cpp
===
--- /dev/null
+++ test/CodeGenCXX/type-names.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -fir-type-names=always -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -fir-type-names=never -o - %s | FileCheck %s --check-prefix=UNNAMED
+
+struct C1 {
+  int a;
+  int *b;
+};
+
+C1 var_C1_a;
+C1 var_C1_b[10];
+C1 *var_C1_c;
+int (*var_C1_d)(const C1 &);
+
+struct C1A {
+  int a;
+  int *b;
+};
+
+C1A var_C1A_a;
+
+template struct C2 {
+  C1 a;
+  T b;
+  struct Inner {
+  };
+};
+
+C2 var_C2_a;
+C2 var_C2_b;
+C2::Inner var_C2_c;
+
+struct C3 {
+  double a;
+  struct C4 {
+int a;
+float b;
+  };
+};
+
+C3::C4 var_c4;
+
+namespace {
+struct C5 {
+  int *a;
+};
+}
+
+C5 var_C5_a;
+void *var_C5_b = &var_C5_a;
+
+// CHECK: %struct.C1 = type { i32, i32* }
+// CHECK: %struct.C1A = type { i32, i32* }
+// CHECK: %struct.C2 = type { %struct.C1, i16 }
+// CHECK: %struct.C2.0 = type { %struct.C1, i64 }
+// CHECK: %"struct.C2::Inner" = type { i8 }
+// CHECK: %"struct.C3::C4" = type { i32, float }
+// CHECK: %"struct.(anonymous namespace)::C5" = type { i32* }
+
+// UNNAMED: %0 = type { i32, i32* }
+// UNNAMED: %1 = type { i32, i32* }
+// UNNAMED: %2 = type { %0, i16 }
+// UNNAMED: %3 = type { %0, i64 }
+// UNNAMED: %4 = type { i8 }
+// UNNAMED: %5 = type { i32, float }
+// UNNAMED: %6 = type { i32* }
Index: test/CodeGenCXX/pr29160.cpp
===
--- test/CodeGenCXX/pr29160.cpp
+++ test/CodeGenCXX/pr29160.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm
+// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu -DNAMELESS -fir-type-names=never %s -o /dev/null -S -emit-llvm
 //
 // This test's failure mode is running ~forever. (For some value of "forever"
 // that's greater than 25 minutes on my machine)
@@ -8,6 +9,7 @@
   template 
   static void ignore() {}
   Foo() { ignore(); }
+  struct ABC {};
 };
 
 struct Base {
@@ -39,3 +41,9 @@
 STAMP(Q, P);
 
 int main() { Q q; }
+
+#ifdef NAMELESS
+// Without '-fir-type-names=none' compiler tries to create name for Q::ABC,
+// which is really huge, so compilation never ends.
+Q::ABC var;
+#endif
Index: lib/Frontend/CompilerInvocation.cpp
===
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -804,6 +804,20 @@
 }
   }
 
+  if (Arg *A = Args.getLastArg(OPT_fir_type_names_EQ)) {
+StringRef Name = A->getValue();
+auto Info = llvm::StringSwitch(Name)
+.Case("auto", CodeGenOptions::IRNames_Auto)
+.Case("never", CodeGenOptions::IRNames_Never)
+.Case("always", CodeGenOptions::IRNames_Always)
+.Default(-1);
+if (Info == -1) {
+  Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+  Success = false;
+} else
+  Opts.setIRTypeNames(static_cast(Info));
+  }
+
   Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type);
   Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
   Opts.InstrumentFunctionsAfterInlining =
Index: lib/Driver/ToolChains/Clang.cpp
===
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -3279,6 +3279,8 @@
   if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO())
 CmdArgs.push_back("-fembed-bitcode=marker");
 
+  Args.AddLastArg(CmdArgs, options::OPT_fir_type_names_EQ);
+
   // We normally speed up the clang process a bit by skipping destructors at
   // exit, but when we're generating diagnostics we can rely on some of the
   // cleanup.
Index: lib/CodeGen/CodeGenTypes.cpp
===
--- lib/CodeGen/CodeGenTypes.cpp
+++ lib/CodeGen/CodeGenTypes.cpp
@@ -51,10 +51,13 @@
 void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
  llvm::StructType *Ty,
  StringRef suffix) {
+  if (getCodeGenOpts().getIRTypeNames() == CodeGenOptions::IRNames_Never)
+return;
+
   SmallString<256> TypeName;
   llvm::raw_svector_ostream OS(TypeName);
   OS << RD->getKindName() << '.';
-  
+
   // Name the codegen type after the typedef name
   // if there is no tag type name available
   if 

[PATCH] D21508: Diagnose friend function template redefinitions

2018-03-13 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 138303.
sepavloff added a comment.

Updated patch

- Rebased relative to recent ToT
- Removed the change in `FunctionDecl::getTemplateInstantiationPattern()`, as 
it is not necessary for error detection,
- Added test for use in module.


Repository:
  rC Clang

https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/Modules/friend-definition.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
Index: test/Modules/friend-definition.cpp
===
--- test/Modules/friend-definition.cpp
+++ test/Modules/friend-definition.cpp
@@ -7,6 +7,7 @@
 #pragma clang module begin A
 template struct A {
   friend A operator+(const A&, const A&) { return {}; }
+  template friend void func_1(const A&, const T2 &) {}
 };
 #pragma clang module end
 #pragma clang module endbuild
@@ -36,4 +37,5 @@
 void h() {
   A a;
   a + a;
+  func_1(a, 0);
 }
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1795,7 +1795,9 @@
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-PrincipalDecl->setObjectOfFriendDecl();
+Function->setObjectOfFriendDecl();
+if (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate())
+  FT->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12321,6 +12321,29 @@
   }
 }
   }
+
+  if (!Definition)
+// Similar to friend functions a friend function template may be a
+// definition and do not have a body if it is instantiated in a class
+// template.
+if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) {
+  for (auto I : FTD->redecls()) {
+auto D = cast(I);
+if (D != FTD) {
+  assert(!D->isThisDeclarationADefinition() &&
+ "More than one definition in redeclaration chain");
+  if (D->getFriendObjectKind() != Decl::FOK_None)
+if (FunctionTemplateDecl *FT =
+   D->getInstantiatedFromMemberTemplate()) {
+  if (FT->isThisDeclarationADefinition()) {
+Definition = D->getTemplatedDecl();
+break;
+  }
+}
+}
+  }
+}
+
   if (!Definition)
 return;
 
Index: include/clang/AST/DeclBase.h
===
--- include/clang/AST/DeclBase.h
+++ include/clang/AST

[PATCH] D44607: Recompute invalidated iterator in insertTargetAndModeArgs

2018-03-19 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Good catch, thank you.

To avoid code duplication you could change `InsertionPoint` into an index and 
use `begin() + InsertionPoint` in calls to `insert`.


Repository:
  rC Clang

https://reviews.llvm.org/D44607



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


[PATCH] D44607: Recompute invalidated iterator in insertTargetAndModeArgs

2018-03-19 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff accepted this revision.
sepavloff added a comment.
This revision is now accepted and ready to land.

LGTM.

Thank you!


Repository:
  rC Clang

https://reviews.llvm.org/D44607



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


[PATCH] D21508: Diagnose friend function template redefinitions

2018-03-19 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Other compilers successfully recognize errors (checked using 
https://godbolt.org/). For instance, the code:

  template inline void func_35(T *x);
  template
  struct C35a {
template friend void func_35(T *x) {}
  };
  template
  struct C35b {
template friend void func_35(T *x) {}
  };
  C35a v35a;
  C35b v35b;

is rejected by MSVC 19:

  example.cpp
  (7): error C2995: 'void func_37(T *)': function template has already 
been defined
  (1): note: see declaration of 'func_37'
  Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x64
  Copyright (C) Microsoft Corporation.  All rights reserved.
  Compiler returned: 2

by  gcc 7.3:

  :7:27: error: redefinition of 'template void func_37(T*)'
   template void func_37(T *x) {}
 ^~~
  :1:27: note: 'template void func_37(T*)' previously declared 
here
   template void func_37(T *x);
 ^~~
  Compiler returned: 1

and icc 18:

  (7): error: function template "func_37" has already been defined
template void func_37(T *x) {}
  ^
  compilation aborted for  (code 2)
  Compiler returned: 2


Repository:
  rC Clang

https://reviews.llvm.org/D21508



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


[PATCH] D44607: Recompute invalidated iterator in insertTargetAndModeArgs

2018-03-19 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL327863: [Driver] Avoid invalidated iterator in 
insertTargetAndModeArgs (authored by sepavloff, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D44607?vs=13&id=138952#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D44607

Files:
  cfe/trunk/tools/driver/driver.cpp


Index: cfe/trunk/tools/driver/driver.cpp
===
--- cfe/trunk/tools/driver/driver.cpp
+++ cfe/trunk/tools/driver/driver.cpp
@@ -212,20 +212,21 @@
   // Put target and mode arguments at the start of argument list so that
   // arguments specified in command line could override them. Avoid putting
   // them at index 0, as an option like '-cc1' must remain the first.
-  auto InsertionPoint = ArgVector.begin();
-  if (InsertionPoint != ArgVector.end())
+  int InsertionPoint = 0;
+  if (ArgVector.size() > 0)
 ++InsertionPoint;
 
   if (NameParts.DriverMode) {
 // Add the mode flag to the arguments.
-ArgVector.insert(InsertionPoint,
+ArgVector.insert(ArgVector.begin() + InsertionPoint,
  GetStableCStr(SavedStrings, NameParts.DriverMode));
   }
 
   if (NameParts.TargetIsValid) {
 const char *arr[] = {"-target", GetStableCStr(SavedStrings,
   NameParts.TargetPrefix)};
-ArgVector.insert(InsertionPoint, std::begin(arr), std::end(arr));
+ArgVector.insert(ArgVector.begin() + InsertionPoint,
+ std::begin(arr), std::end(arr));
   }
 }
 


Index: cfe/trunk/tools/driver/driver.cpp
===
--- cfe/trunk/tools/driver/driver.cpp
+++ cfe/trunk/tools/driver/driver.cpp
@@ -212,20 +212,21 @@
   // Put target and mode arguments at the start of argument list so that
   // arguments specified in command line could override them. Avoid putting
   // them at index 0, as an option like '-cc1' must remain the first.
-  auto InsertionPoint = ArgVector.begin();
-  if (InsertionPoint != ArgVector.end())
+  int InsertionPoint = 0;
+  if (ArgVector.size() > 0)
 ++InsertionPoint;
 
   if (NameParts.DriverMode) {
 // Add the mode flag to the arguments.
-ArgVector.insert(InsertionPoint,
+ArgVector.insert(ArgVector.begin() + InsertionPoint,
  GetStableCStr(SavedStrings, NameParts.DriverMode));
   }
 
   if (NameParts.TargetIsValid) {
 const char *arr[] = {"-target", GetStableCStr(SavedStrings,
   NameParts.TargetPrefix)};
-ArgVector.insert(InsertionPoint, std::begin(arr), std::end(arr));
+ArgVector.insert(ArgVector.begin() + InsertionPoint,
+ std::begin(arr), std::end(arr));
   }
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D21508: Diagnose friend function template redefinitions

2018-12-04 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 176763.
sepavloff added a comment.

Updated patch

The fix for https://bugs.llvm.org/show_bug.cgi?id=39742 put a test
case, which is not a valid code. The error is detected with this
patch, tests are updated accordingly.


Repository:
  rC Clang

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

https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/Modules/friend-definition.cpp
  test/SemaCXX/friend-template-redecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
@@ -235,3 +312,15 @@
   cache.insert();
 }
 }
+
+namespace PR39742 {
+template
+struct wrapper {
+  template
+  friend void friend_function_template() {}  // expected-error{{redefinition of 'friend_function_template'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+wrapper x;
+wrapper y;  // expected-note{{in instantiation of template class 'PR39742::wrapper' requested here}}
+}
Index: test/SemaCXX/friend-template-redecl.cpp
===
--- test/SemaCXX/friend-template-redecl.cpp
+++ test/SemaCXX/friend-template-redecl.cpp
@@ -18,14 +18,3 @@
   foo(x);
   bar(x);
 }
-
-namespace PR39742 {
-template
-struct wrapper {
-  template
-  friend void friend_function_template() {}
-};
-
-wrapper x;
-wrapper y;
-}
Index: test/Modules/friend-definition.cpp
===
--- test/Modules/friend-definition.cpp
+++ test/Modules/friend-definition.cpp
@@ -7,6 +7,7 @@
 #pragma clang module begin A
 template struct A {
   friend A operator+(const A&, const A&) { return {}; }
+  template friend void func_1(const A&, const T2 &) {}
 };
 #pragma clang module end
 #pragma clang module endbuild
@@ -36,4 +37,5 @@
 void h() {
   A a;
   a + a;
+  func_1(a, 0);
 }
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1817,7 +1817,9 @@
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-PrincipalDecl->setObjectOfFriendDecl();
+Function->setObjectOfFriendDecl();
+if (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate())
+  FT->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12744,6 +12744,29 @@
   }
 }
   }
+
+  if (!Definition)
+// Similar to friend functions a friend function template may be a
+// definition and do not have a b

[PATCH] D21508: Diagnose friend function template redefinitions

2018-12-06 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL348473: Diagnose friend function template redefinitions. 
(authored by sepavloff, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D21508?vs=176763&id=176938#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D21508

Files:
  cfe/trunk/include/clang/AST/DeclBase.h
  cfe/trunk/lib/Sema/SemaDecl.cpp
  cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
  cfe/trunk/test/Modules/friend-definition.cpp
  cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
  cfe/trunk/test/SemaCXX/friend2.cpp

Index: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1817,7 +1817,9 @@
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-PrincipalDecl->setObjectOfFriendDecl();
+Function->setObjectOfFriendDecl();
+if (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate())
+  FT->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: cfe/trunk/lib/Sema/SemaDecl.cpp
===
--- cfe/trunk/lib/Sema/SemaDecl.cpp
+++ cfe/trunk/lib/Sema/SemaDecl.cpp
@@ -12737,6 +12737,29 @@
   }
 }
   }
+
+  if (!Definition)
+// Similar to friend functions a friend function template may be a
+// definition and do not have a body if it is instantiated in a class
+// template.
+if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) {
+  for (auto I : FTD->redecls()) {
+auto D = cast(I);
+if (D != FTD) {
+  assert(!D->isThisDeclarationADefinition() &&
+ "More than one definition in redeclaration chain");
+  if (D->getFriendObjectKind() != Decl::FOK_None)
+if (FunctionTemplateDecl *FT =
+   D->getInstantiatedFromMemberTemplate()) {
+  if (FT->isThisDeclarationADefinition()) {
+Definition = D->getTemplatedDecl();
+break;
+  }
+}
+}
+  }
+}
+
   if (!Definition)
 return;
 
Index: cfe/trunk/include/clang/AST/DeclBase.h
===
--- cfe/trunk/include/clang/AST/DeclBase.h
+++ cfe/trunk/include/clang/AST/DeclBase.h
@@ -1065,11 +1065,11 @@
 unsigned OldNS = IdentifierNamespace;
 assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
  IDNS_TagFriend | IDNS_OrdinaryFriend |
- IDNS_LocalExtern)) &&
+ IDNS_LocalExtern | IDNS_NonMemberOperator)) &&
"namespace includes neither ordinary nor tag");
 assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
IDNS_TagFriend | IDNS_OrdinaryFriend |
-   IDNS_LocalExtern)) &&
+   IDNS_LocalExtern | IDNS_NonMemberOperator)) &&
"namespace includes other than ordinary or tag");
 
 Decl *Prev = getPreviousDecl();
@@ -1082,7 +1082,8 @@
 IdentifierNamespace |= IDNS_Tag | IDNS_Type;
 }
 
-if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) {
+if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend |
+ IDNS_LocalExtern | IDNS_NonMemberOperator)) {
   IdentifierNamespace |= IDNS_OrdinaryFriend;
   if (PerformFriendInjection ||
   (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
Index: cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
===
--- cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
+++ cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
@@ -18,16 +18,3 @@
   foo(x);
   bar(x);
 }
-
-namespace PR39742 {
-template
-struct wrapper {
-  template
-  friend void friend_function_template() {}
-};
-
-wrapper x;
-// FIXME: We should really error here because of the redefinition of
-// friend_function_template.
-wrapper y;
-}
Index: cfe/trunk/test/SemaCXX/friend2.cpp
===
--- cfe/trunk/test/SemaCXX/friend2.cpp
+++ cfe/trunk/test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {

[PATCH] D36057: Use class to pass information about executable name

2017-08-28 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL311981: Use class to pass information about executable name 
(authored by sepavloff).

Repository:
  rL LLVM

https://reviews.llvm.org/D36057

Files:
  cfe/trunk/include/clang/Driver/Driver.h
  cfe/trunk/include/clang/Driver/ToolChain.h
  cfe/trunk/lib/Driver/Driver.cpp
  cfe/trunk/lib/Driver/ToolChain.cpp
  cfe/trunk/lib/Tooling/Tooling.cpp
  cfe/trunk/tools/driver/driver.cpp
  cfe/trunk/unittests/Driver/CMakeLists.txt
  cfe/trunk/unittests/Driver/ToolChainTest.cpp

Index: cfe/trunk/lib/Tooling/Tooling.cpp
===
--- cfe/trunk/lib/Tooling/Tooling.cpp
+++ cfe/trunk/lib/Tooling/Tooling.cpp
@@ -190,11 +190,12 @@
 }
 auto TargetMode =
 clang::driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs);
-if (!AlreadyHasMode && !TargetMode.second.empty()) {
-  CommandLine.insert(++CommandLine.begin(), TargetMode.second);
+if (!AlreadyHasMode && TargetMode.DriverMode) {
+  CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
 }
-if (!AlreadyHasTarget && !TargetMode.first.empty()) {
-  CommandLine.insert(++CommandLine.begin(), {"-target", TargetMode.first});
+if (!AlreadyHasTarget && TargetMode.TargetIsValid) {
+  CommandLine.insert(++CommandLine.begin(), {"-target",
+ TargetMode.TargetPrefix});
 }
   }
 }
Index: cfe/trunk/lib/Driver/Driver.cpp
===
--- cfe/trunk/lib/Driver/Driver.cpp
+++ cfe/trunk/lib/Driver/Driver.cpp
@@ -119,9 +119,8 @@
 
 void Driver::ParseDriverMode(StringRef ProgramName,
  ArrayRef Args) {
-  auto Default = ToolChain::getTargetAndModeFromProgramName(ProgramName);
-  StringRef DefaultMode(Default.second);
-  setDriverModeFromOption(DefaultMode);
+  ClangNameParts = ToolChain::getTargetAndModeFromProgramName(ProgramName);
+  setDriverModeFromOption(ClangNameParts.DriverMode);
 
   for (const char *ArgPtr : Args) {
 // Ingore nullptrs, they are response file's EOL markers
Index: cfe/trunk/lib/Driver/ToolChain.cpp
===
--- cfe/trunk/lib/Driver/ToolChain.cpp
+++ cfe/trunk/lib/Driver/ToolChain.cpp
@@ -113,7 +113,7 @@
   const char *ModeFlag;
 };
 
-const DriverSuffix *FindDriverSuffix(StringRef ProgName) {
+const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
   // A list of known driver suffixes. Suffixes are compared against the
   // program name in order. If there is a match, the frontend type is updated as
   // necessary by applying the ModeFlag.
@@ -132,9 +132,13 @@
   {"++", "--driver-mode=g++"},
   };
 
-  for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i)
-if (ProgName.endswith(DriverSuffixes[i].Suffix))
+  for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) {
+StringRef Suffix(DriverSuffixes[i].Suffix);
+if (ProgName.endswith(Suffix)) {
+  Pos = ProgName.size() - Suffix.size();
   return &DriverSuffixes[i];
+}
+  }
   return nullptr;
 }
 
@@ -149,55 +153,54 @@
   return ProgName;
 }
 
-const DriverSuffix *parseDriverSuffix(StringRef ProgName) {
+const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) {
   // Try to infer frontend type and default target from the program name by
   // comparing it against DriverSuffixes in order.
 
   // If there is a match, the function tries to identify a target as prefix.
   // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target
   // prefix "x86_64-linux". If such a target prefix is found, it may be
   // added via -target as implicit first argument.
-  const DriverSuffix *DS = FindDriverSuffix(ProgName);
+  const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos);
 
   if (!DS) {
 // Try again after stripping any trailing version number:
 // clang++3.5 -> clang++
 ProgName = ProgName.rtrim("0123456789.");
-DS = FindDriverSuffix(ProgName);
+DS = FindDriverSuffix(ProgName, Pos);
   }
 
   if (!DS) {
 // Try again after stripping trailing -component.
 // clang++-tot -> clang++
 ProgName = ProgName.slice(0, ProgName.rfind('-'));
-DS = FindDriverSuffix(ProgName);
+DS = FindDriverSuffix(ProgName, Pos);
   }
   return DS;
 }
 } // anonymous namespace
 
-std::pair
+ParsedClangName
 ToolChain::getTargetAndModeFromProgramName(StringRef PN) {
   std::string ProgName = normalizeProgramName(PN);
-  const DriverSuffix *DS = parseDriverSuffix(ProgName);
+  size_t SuffixPos;
+  const DriverSuffix *DS = parseDriverSuffix(ProgName, SuffixPos);
   if (!DS)
-return std::make_pair("", "");
-  std::string ModeFlag = DS->ModeFlag == nullptr ? "" : DS->ModeFlag;
+return ParsedClangName();
+  size_t SuffixEnd = SuffixPos + strlen(DS->Suffix);
 
-  std::string::size_type LastComponent =
-  Pr

[PATCH] D36057: Use class to pass information about executable name

2017-08-28 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

@echristo Committed, thanks.


Repository:
  rL LLVM

https://reviews.llvm.org/D36057



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


[PATCH] D30170: Function definition may have uninstantiated body

2017-09-16 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 115534.
sepavloff added a comment.

Rebased patch.


https://reviews.llvm.org/D30170

Files:
  include/clang/AST/Decl.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -101,6 +101,34 @@
   friend void func_12(int x = 0);  // expected-error{{friend declaration specifying a default argument must be the only declaration}}
 };
 
+// Friend function with uninstantiated body is still a definition.
+
+template struct C20 {
+  friend void func_20() {} // expected-note{{previous definition is here}}
+};
+C20 c20i;
+void func_20() {} // expected-error{{redefinition of 'func_20'}}
+
+template struct C21a {
+  friend void func_21() {} // expected-note{{previous definition is here}}
+};
+template struct C21b {
+  friend void func_21() {} // expected-error{{redefinition of 'func_21'}}
+};
+C21a c21ai;
+C21b c21bi; // expected-note{{in instantiation of template class 'C21b' requested here}}
+
+template struct C22a {
+  friend void func_22() {} // expected-note{{previous definition is here}}
+};
+template struct C22b {
+  friend void func_22();
+};
+C22a c22ai;
+C22b c22bi;
+void func_22() {} // expected-error{{redefinition of 'func_22'}}
+
+
 
 namespace pr22307 {
 
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1807,45 +1807,24 @@
 //   apply to non-template function declarations and definitions also apply
 //   to these implicit definitions.
 if (D->isThisDeclarationADefinition()) {
-  // Check for a function body.
-  const FunctionDecl *Definition = nullptr;
-  if (Function->isDefined(Definition) &&
-  Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
-SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
-<< Function->getDeclName();
-SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
-  }
-  // Check for redefinitions due to other instantiations of this or
-  // a similar friend function.
-  else for (auto R : Function->redecls()) {
-if (R == Function)
-  continue;
-
-// If some prior declaration of this function has been used, we need
-// to instantiate its definition.
-if (!QueuedInstantiation && R->isUsed(false)) {
-  if (MemberSpecializationInfo *MSInfo =
-  Function->getMemberSpecializationInfo()) {
-if (MSInfo->getPointOfInstantiation().isInvalid()) {
-  SourceLocation Loc = R->getLocation(); // FIXME
-  MSInfo->setPointOfInstantiation(Loc);
-  SemaRef.PendingLocalImplicitInstantiations.push_back(
-   std::make_pair(Function, Loc));
-  QueuedInstantiation = true;
-}
-  }
-}
-
-// If some prior declaration of this function was a friend with an
-// uninstantiated definition, reject it.
-if (R->getFriendObjectKind()) {
-  if (const FunctionDecl *RPattern =
-  R->getTemplateInstantiationPattern()) {
-if (RPattern->isDefined(RPattern)) {
-  SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
-<< Function->getDeclName();
-  SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
-  break;
+  SemaRef.CheckForFunctionRedefinition(Function);
+  if (!Function->isInvalidDecl()) {
+for (auto R : Function->redecls()) {
+  if (R == Function)
+continue;
+
+  // If some prior declaration of this function has been used, we need
+  // to instantiate its definition.
+  if (!QueuedInstantiation && R->isUsed(false)) {
+if (MemberSpecializationInfo *MSInfo =
+Function->getMemberSpecializationInfo()) {
+  if (MSInfo->getPointOfInstantiation().isInvalid()) {
+SourceLocation Loc = R->getLocation(); // FIXME
+MSInfo->setPointOfInstantiation(Loc);
+SemaRef.PendingLocalImplicitInstantiations.push_back(
+std::make_pair(Function, Loc));
+QueuedInstantiation = true;
+  }
 }
   }
 }
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11981,9 +11981,31 @@
const FunctionDecl *EffectiveDefinition,
SkipBodyInfo *SkipBody) {
   const FunctionDecl *Definition = EffectiveDefinition;
+  if (!Definition &&
+  !FD->is

[PATCH] D21508: Diagnose friend function template redefinitions

2017-09-16 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 115539.
sepavloff added a comment.

Rebased


https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/AST/Decl.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1795,7 +1795,9 @@
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-PrincipalDecl->setObjectOfFriendDecl();
+Function->setObjectOfFriendDecl();
+if (FunctionTemplate)
+  FunctionTemplate->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12004,6 +12004,29 @@
   }
 }
   }
+
+  if (!Definition)
+// Similar to friend functions a friend function template may be a
+// definition and do not have a body if it is instantiated in a class
+// template.
+if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) {
+  for (auto I : FTD->redecls()) {
+auto D = cast(I);
+if (D != FTD) {
+  assert(!D->isThisDeclarationADefinition() &&
+ "Underlying function declaration must be a definition");
+  if (D->getFriendObjectKind() != Decl::FOK_None)
+if (FunctionTemplateDecl *FT =
+   D->getInstantiatedFromMemberTemplate()) {
+  if (FT->isThisDeclarationADefinition()) {
+Definition = D->getTemplatedDecl();
+break;
+  }
+}
+}
+  }
+}
+
   if (!Definition)
 return;
 
Index: lib/AST/Decl.cpp
===
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3267,6 +3267,14 @@
   if (auto *MFD = getInstantiatedFromMemberFunction())
 return getDefinitionOrSelf(MFD);
 
+  if (FunctionTemplateDecl *TD = getDescribedFunctionTemplate()) {
+if (TD->getFriendObjectKind() != FOK_None) {
+  while (FunctionTemplateDecl *FT = TD->getInstantiatedFromMemberTemplate())
+TD = FT;
+  return TD->getTemplatedDecl();
+}
+  }
+
   return nullptr;
 }
 
Index: include/clang/AST/DeclBase.h
===
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -1034,11 +1034,11 @@
 unsigned OldNS = IdentifierNamespace;
 assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
  IDNS_TagFriend | IDNS_OrdinaryFriend |
- IDNS_

[PATCH] D21767: Fix instantiation of friend function templates

2017-09-25 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 116484.
sepavloff edited the summary of this revision.
sepavloff added a comment.

Added regression test for PR34343

Investigation of this defect is presented in 
https://bugs.llvm.org/show_bug.cgi?id=34343 .


https://reviews.llvm.org/D21767

Files:
  include/clang/AST/ASTLambda.h
  include/clang/AST/Decl.h
  include/clang/Sema/Sema.h
  lib/AST/Decl.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaTemplate/instantiate-friend-function.cpp

Index: test/SemaTemplate/instantiate-friend-function.cpp
===
--- test/SemaTemplate/instantiate-friend-function.cpp
+++ test/SemaTemplate/instantiate-friend-function.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -S -triple %itanium_abi_triple -std=c++11 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -S -triple %itanium_abi_triple -std=c++11 -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s
 // expected-no-diagnostics
 
 namespace PR10856 {
@@ -47,3 +47,572 @@
 
 // bool PR10856_Root::g, void>(PR10856_Root::MyClass)
 // CHECK: call {{.*}} @_ZN12PR10856_Root1gINS_7MyClassIiEEvEEbT_
+
+// Instantiate friend function, pattern is at file level.
+
+
+template struct C01 {
+  template friend void func_01(C01 &, T1);
+  template friend void func_01a(C01 &, T2);
+};
+
+C01 c01;
+
+void f_01() {
+  func_01(c01, 0.0);
+  func_01a(c01, 0.0);
+}
+
+template void func_01(C01 &, T1) {}
+template void func_01a(C01 &, T2) {}
+
+// void func_01(C01&, double)
+// CHECK: define linkonce_odr void @_Z7func_01IdEvR3C01IiET_
+//
+// void func_01a(C01&, double)
+// CHECK: define linkonce_odr void @_Z8func_01aIidEvR3C01IT_ET0_
+
+
+template struct C02 {
+  template friend void func_02(const C02 &, T1) { T var; }
+  template friend void func_02a(const C02 &, T2) { T var; }
+  template friend constexpr unsigned func_02b(const C02 &, const T1 x) { return sizeof(T1); }
+};
+
+const C02 c02;
+
+void f_02() {
+  func_02(c02, 0.0);
+  func_02a(c02, 0.0);
+  static_assert(func_02b(c02, short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_02b(c02, 122L) == sizeof(long), "Invalid calculation");
+}
+
+// void func_02(C02 const&, double)
+// CHECK: define linkonce_odr void @_Z7func_02IdEvRK3C02IiET_
+//
+// void func_02a(C02 const&, double)
+// CHECK: define linkonce_odr void @_Z8func_02aIidEvRK3C02IT_ET0_
+
+
+template struct C03 {
+  template friend void func_03(C03 &, T1);
+  template friend void func_03a(C03 &, T2);
+};
+
+C03 c03;
+
+void f_03() {
+  func_03(c03, 0.0);
+  func_03a(c03, 0.0);
+}
+
+template struct C03A {
+  template friend void func_03(C03 &, T1) { }
+};
+template struct C03B {
+  template friend void func_03a(C03 &, T2) { T var; }
+};
+
+C03A c03a;
+C03B c03b;
+
+// void func_03(C03&, double)
+// CHECK: define linkonce_odr void @_Z7func_03IdEvR3C03IiET_  
+//
+// void func_03a(C03&, double)
+// CHECK: define linkonce_odr void @_Z8func_03aIidEvR3C03IT_ET0_
+
+
+// File level declaration, friend pattern.
+
+
+template void func_10(T1 *x);
+template void func_10a(T1 *x, T2 *y);
+template constexpr unsigned func_10b(const T1 x);
+template constexpr unsigned func_10c(const T1 x);
+
+template
+struct C10 {
+  template friend void func_10(T1 *x) { T var; }
+  template friend void func_10a(T1 *x, T2 *y) { T var; }
+  template friend constexpr unsigned func_10b(const T1 x) { return sizeof(T1); }
+  template friend constexpr unsigned func_10c(const T1 x) { return sizeof(T); }
+};
+
+C10 v10;
+
+void use_10(int *x) {
+  func_10(x);
+  func_10a(x, &x);
+  static_assert(func_10b(short(122)) == sizeof(short), "Invalid calculation");
+  static_assert(func_10b(122L) == sizeof(long), "Invalid calculation");
+  static_assert(func_10c(short(122)) == sizeof(int), "Invalid calculation");
+  static_assert(func_10c(122L) == sizeof(int), "Invalid calculation");
+}
+
+// void func_10(int*)
+// CHECK: define linkonce_odr void @_Z7func_10IiEvPT_
+//
+// void func_10a(int*, int**)
+// CHECK: define linkonce_odr void @_Z8func_10aIiPiEvPT_PT0_
+
+
+template
+struct C11 {
+  template friend void func_11(T1 *x) { T var; }
+  template friend void func_11a(T1 *x, T2 *y) { T var; }
+  template friend constexpr unsigned func_11b(const T1 x) { return sizeof(T1); }
+  template friend constexpr unsigned func_11c(const T1 x) { return sizeof(T); }
+};
+
+C11 v11;
+
+template void func_11(T *x);
+template void func_11a(T1 *x, T2 *y);
+template constexpr unsigned func_11b(const T1 x);
+template constexpr unsigned func_11c(const T1 x);
+
+void use_11(int *x) {
+  func_11(x);
+  func_11a(x, &x);
+  static_assert(func_11b(short(123)) == sizeof(short), "Invalid calculation");
+  static_assert(func_11b(123L) == sizeof(long), "Invalid calculation");
+  static_assert(func_11c(short(123)) == sizeof(int), "Invalid calculation");
+  stati

[PATCH] D64932: [Parser] Emit descriptive diagnostic for misplaced pragma

2019-07-18 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: rsmith, rjmccall, erik.pilkington, ABataev.
Herald added a subscriber: dexonsmith.
Herald added a project: clang.

If a class or struct or union declaration contains a pragma that
is not valid in this context, compiler issues generic error like
"expected member name or ';' after declaration specifiers". With this
change the error tells that this pragma cannot appear in this declaration.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D64932

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Basic/TokenKinds.h
  clang/include/clang/Parse/Parser.h
  clang/lib/Basic/TokenKinds.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/Parser.cpp
  clang/test/Parser/pragma-attribute-context.cpp
  clang/test/Parser/pragma-fp-contract.c
  clang/test/Parser/pragma-fp-contract.cpp

Index: clang/test/Parser/pragma-fp-contract.cpp
===
--- /dev/null
+++ clang/test/Parser/pragma-fp-contract.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f1(void) {
+  int x = 0;
+/* expected-error@+1 {{'#pragma fp_contract' can only appear at file scope or at the start of a compound statement}} */
+#pragma STDC FP_CONTRACT ON
+}
+
+void f2(void) {
+  #pragma STDC FP_CONTRACT OFF
+  #pragma STDC FP_CONTRACT ON 
+}
+
+struct S1 {
+// expected-error@+1 {{this pragma cannot appear in struct declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f1;
+};
+
+union U1 {
+  float f1;
+  float f2;
+// expected-error@+1 {{this pragma cannot appear in union declaration}}
+#pragma STDC FP_CONTRACT ON
+};
+
+class C1 {
+  float f1;
+// expected-error@+1 {{this pragma cannot appear in class declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f2;
+};
Index: clang/test/Parser/pragma-fp-contract.c
===
--- clang/test/Parser/pragma-fp-contract.c
+++ clang/test/Parser/pragma-fp-contract.c
@@ -10,3 +10,16 @@
   #pragma STDC FP_CONTRACT OFF
   #pragma STDC FP_CONTRACT ON 
 }
+
+struct S1 {
+// expected-error@+1 {{this pragma cannot appear in struct declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f1;
+};
+
+union U1 {
+  float f1;
+  float f2;
+// expected-error@+1 {{this pragma cannot appear in union declaration}}
+#pragma STDC FP_CONTRACT ON
+};
Index: clang/test/Parser/pragma-attribute-context.cpp
===
--- clang/test/Parser/pragma-attribute-context.cpp
+++ clang/test/Parser/pragma-attribute-context.cpp
@@ -31,8 +31,7 @@
 
 struct InStruct {
   // FIXME: This asserts in Objective-C++!
-  // FIXME: This is a horrible diagnostic!
 #ifndef __OBJC__
-  BEGIN_PRAGMA // expected-error {{expected member name or ';' after declaration specifiers}}
+  BEGIN_PRAGMA // expected-error {{this pragma cannot appear in struct declaration}}
 #endif
 };
Index: clang/lib/Parse/Parser.cpp
===
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -174,7 +174,7 @@
   return ExpectAndConsume(tok::semi, DiagID);
 }
 
-void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
+void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
   if (!Tok.is(tok::semi)) return;
 
   bool HadMultipleSemis = false;
@@ -202,7 +202,7 @@
 
   if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis)
 Diag(StartLoc, diag::ext_extra_semi)
-<< Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST,
+<< Kind << DeclSpec::getSpecifierName(TST,
 Actions.getASTContext().getPrintingPolicy())
 << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
   else
Index: clang/lib/Parse/ParseDeclCXX.cpp
===
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -3134,6 +3134,13 @@
   TagDecl);
 
   default:
+if (tok::isPragmaAnnotation(Tok.getKind())) {
+  Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+  << DeclSpec::getSpecifierName(TagType,
+   Actions.getASTContext().getPrintingPolicy());
+  ConsumeAnnotationToken();
+  return nullptr;
+}
 return ParseCXXClassMemberDeclaration(AS, AccessAttrs);
   }
 }
@@ -4337,7 +4344,7 @@
   while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
 // __if_exists, __if_not_exists can nest.
 if (Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
-  ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType,
+  ParseMicrosoftIfExistsClassDeclaration(TagType,
  AccessAttrs, CurAS);
   continue;
 }
Index: clang/lib/Parse/ParseDecl.cpp

[PATCH] D64932: [Parser] Emit descriptive diagnostic for misplaced pragma

2019-07-26 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Ping.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D64932



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


[PATCH] D65405: [Parser] Use special definition for pragma annotations

2019-07-29 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: rsmith, rjmccall.
Herald added a reviewer: jdoerfert.
Herald added a project: clang.

Previously pragma annotation tokens were described as any other
annotations in TokenKinds.def. This change introduces special macro
PRAGMA_ANNOTATION for the pragma descriptions. It allows implementing
checks that deal with pragma annotations only.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D65405

Files:
  clang/include/clang/Basic/TokenKinds.def
  clang/include/clang/Basic/TokenKinds.h
  clang/lib/Basic/TokenKinds.cpp

Index: clang/lib/Basic/TokenKinds.cpp
===
--- clang/lib/Basic/TokenKinds.cpp
+++ clang/lib/Basic/TokenKinds.cpp
@@ -45,3 +45,13 @@
   }
   return nullptr;
 }
+
+bool tok::isPragmaAnnotation(TokenKind Kind) {
+  switch (Kind) {
+#define PRAGMA_ANNOTATION(X) case annot_ ## X: return true;
+#include "clang/Basic/TokenKinds.def"
+  default:
+break;
+  }
+  return false;
+}
Index: clang/include/clang/Basic/TokenKinds.h
===
--- clang/include/clang/Basic/TokenKinds.h
+++ clang/include/clang/Basic/TokenKinds.h
@@ -98,6 +98,9 @@
   return false;
 }
 
+/// Return true if this is an annotation token representing a pragma.
+bool isPragmaAnnotation(TokenKind K);
+
 }  // end namespace tok
 }  // end namespace clang
 
Index: clang/include/clang/Basic/TokenKinds.def
===
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -68,6 +68,9 @@
 #ifndef ANNOTATION
 #define ANNOTATION(X) TOK(annot_ ## X)
 #endif
+#ifndef PRAGMA_ANNOTATION
+#define PRAGMA_ANNOTATION(X) ANNOTATION(X)
+#endif
 
 //===--===//
 // Preprocessor keywords.
@@ -729,103 +732,103 @@
 // Annotation for #pragma unused(...)
 // For each argument inside the parentheses the pragma handler will produce
 // one 'pragma_unused' annotation token followed by the argument token.
-ANNOTATION(pragma_unused)
+PRAGMA_ANNOTATION(pragma_unused)
 
 // Annotation for #pragma GCC visibility...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_vis)
+PRAGMA_ANNOTATION(pragma_vis)
 
 // Annotation for #pragma pack...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_pack)
+PRAGMA_ANNOTATION(pragma_pack)
 
 // Annotation for #pragma clang __debug parser_crash...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_parser_crash)
+PRAGMA_ANNOTATION(pragma_parser_crash)
 
 // Annotation for #pragma clang __debug captured...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_captured)
+PRAGMA_ANNOTATION(pragma_captured)
 
 // Annotation for #pragma clang __debug dump...
 // The lexer produces these so that the parser and semantic analysis can
 // look up and dump the operand.
-ANNOTATION(pragma_dump)
+PRAGMA_ANNOTATION(pragma_dump)
 
 // Annotation for #pragma ms_struct...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_msstruct)
+PRAGMA_ANNOTATION(pragma_msstruct)
 
 // Annotation for #pragma align...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_align)
+PRAGMA_ANNOTATION(pragma_align)
 
 // Annotation for #pragma weak id
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_weak)
+PRAGMA_ANNOTATION(pragma_weak)
 
 // Annotation for #pragma weak id = id
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_weakalias)
+PRAGMA_ANNOTATION(pragma_weakalias)
 
 // Annotation for #pragma redefine_extname...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_redefine_extname)
+PRAGMA_ANNOTATION(pragma_redefine_extname)
 
 // Annotation for #pragma STDC FP_CONTRACT...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_fp_contract)
+PRAGMA_ANNOTATION(pragma_fp_contract)
 
 // Annotation for #pragma STDC FENV_ACCESS
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_fenv_access)
+PRAGMA_ANNOTATION(pragma_fenv_access)
 
 // Annotation for #pragma pointers_to_members...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_ms_pointers_to_members)
+PRAGMA_ANNOTATION(pragma_ms_pointers_to_members)
 
 // Annotation for #pragma vtordisp...
 // The lexer produces these so that they only take effect when

[PATCH] D65406: [Parser] Change parameter type from int to enum

2019-07-29 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: rsmith, rjmccall.
Herald added a project: clang.

Some parser functions accept argument of type unsigned while it is
actually of type DeclSpec::TST. No functional changes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D65406

Files:
  clang/include/clang/Parse/Parser.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/Parser.cpp


Index: clang/lib/Parse/Parser.cpp
===
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -174,7 +174,7 @@
   return ExpectAndConsume(tok::semi, DiagID);
 }
 
-void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
+void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
   if (!Tok.is(tok::semi)) return;
 
   bool HadMultipleSemis = false;
@@ -202,7 +202,7 @@
 
   if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis)
 Diag(StartLoc, diag::ext_extra_semi)
-<< Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST,
+<< Kind << DeclSpec::getSpecifierName(TST,
 
Actions.getASTContext().getPrintingPolicy())
 << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
   else
Index: clang/lib/Parse/ParseDeclCXX.cpp
===
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -4337,7 +4337,7 @@
   while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
 // __if_exists, __if_not_exists can nest.
 if (Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
-  ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType,
+  ParseMicrosoftIfExistsClassDeclaration(TagType,
  AccessAttrs, CurAS);
   continue;
 }
Index: clang/lib/Parse/ParseDecl.cpp
===
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -4098,7 +4098,7 @@
 /// [OBC]   '@' 'defs' '(' class-name ')'
 ///
 void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
-  unsigned TagType, Decl *TagDecl) {
+  DeclSpec::TST TagType, Decl *TagDecl) {
   PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
   "parsing struct/union body");
   assert(!getLangOpts().CPlusPlus && "C++ declarations not supported");
Index: clang/include/clang/Parse/Parser.h
===
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -972,7 +972,7 @@
   };
 
   /// Consume any extra semi-colons until the end of the line.
-  void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified);
+  void ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST T = TST_unspecified);
 
   /// Return false if the next token is an identifier. An 'expected identifier'
   /// error is emitted otherwise.
@@ -2160,7 +2160,7 @@
   const ParsedTemplateInfo &TemplateInfo,
   AccessSpecifier AS, DeclSpecContext DSC);
   void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl);
-  void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
+  void ParseStructUnionBody(SourceLocation StartLoc, DeclSpec::TST TagType,
 Decl *TagDecl);
 
   void ParseStructDeclaration(


Index: clang/lib/Parse/Parser.cpp
===
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -174,7 +174,7 @@
   return ExpectAndConsume(tok::semi, DiagID);
 }
 
-void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
+void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
   if (!Tok.is(tok::semi)) return;
 
   bool HadMultipleSemis = false;
@@ -202,7 +202,7 @@
 
   if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis)
 Diag(StartLoc, diag::ext_extra_semi)
-<< Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST,
+<< Kind << DeclSpec::getSpecifierName(TST,
 Actions.getASTContext().getPrintingPolicy())
 << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
   else
Index: clang/lib/Parse/ParseDeclCXX.cpp
===
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -4337,7 +4337,7 @@
   while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
 // __if_exists, __if_not_exists can nest.
 if (Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
-  ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType,
+  ParseMicrosoftIfExistsClassDeclaration(TagType,
  AccessAttrs, CurAS);
   co

[PATCH] D64932: [Parser] Emit descriptive diagnostic for misplaced pragma

2019-07-29 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 212188.
sepavloff added a comment.

Updated patch

Move logically independent changes to separate patches.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D64932

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Basic/TokenKinds.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/test/Parser/pragma-attribute-context.cpp
  clang/test/Parser/pragma-fp-contract.c
  clang/test/Parser/pragma-fp-contract.cpp

Index: clang/test/Parser/pragma-fp-contract.cpp
===
--- /dev/null
+++ clang/test/Parser/pragma-fp-contract.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f1(void) {
+  int x = 0;
+/* expected-error@+1 {{'#pragma fp_contract' can only appear at file scope or at the start of a compound statement}} */
+#pragma STDC FP_CONTRACT ON
+}
+
+void f2(void) {
+  #pragma STDC FP_CONTRACT OFF
+  #pragma STDC FP_CONTRACT ON 
+}
+
+struct S1 {
+// expected-error@+1 {{this pragma cannot appear in struct declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f1;
+};
+
+union U1 {
+  float f1;
+  float f2;
+// expected-error@+1 {{this pragma cannot appear in union declaration}}
+#pragma STDC FP_CONTRACT ON
+};
+
+class C1 {
+  float f1;
+// expected-error@+1 {{this pragma cannot appear in class declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f2;
+};
Index: clang/test/Parser/pragma-fp-contract.c
===
--- clang/test/Parser/pragma-fp-contract.c
+++ clang/test/Parser/pragma-fp-contract.c
@@ -10,3 +10,16 @@
   #pragma STDC FP_CONTRACT OFF
   #pragma STDC FP_CONTRACT ON 
 }
+
+struct S1 {
+// expected-error@+1 {{this pragma cannot appear in struct declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f1;
+};
+
+union U1 {
+  float f1;
+  float f2;
+// expected-error@+1 {{this pragma cannot appear in union declaration}}
+#pragma STDC FP_CONTRACT ON
+};
Index: clang/test/Parser/pragma-attribute-context.cpp
===
--- clang/test/Parser/pragma-attribute-context.cpp
+++ clang/test/Parser/pragma-attribute-context.cpp
@@ -31,8 +31,7 @@
 
 struct InStruct {
   // FIXME: This asserts in Objective-C++!
-  // FIXME: This is a horrible diagnostic!
 #ifndef __OBJC__
-  BEGIN_PRAGMA // expected-error {{expected member name or ';' after declaration specifiers}}
+  BEGIN_PRAGMA // expected-error {{this pragma cannot appear in struct declaration}}
 #endif
 };
Index: clang/lib/Parse/ParseDeclCXX.cpp
===
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -3134,6 +3134,13 @@
   TagDecl);
 
   default:
+if (tok::isPragmaAnnotation(Tok.getKind())) {
+  Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+  << DeclSpec::getSpecifierName(TagType,
+   Actions.getASTContext().getPrintingPolicy());
+  ConsumeAnnotationToken();
+  return nullptr;
+}
 return ParseCXXClassMemberDeclaration(AS, AccessAttrs);
   }
 }
Index: clang/lib/Parse/ParseDecl.cpp
===
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -4148,6 +4148,14 @@
   continue;
 }
 
+if (tok::isPragmaAnnotation(Tok.getKind())) {
+  Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+  << DeclSpec::getSpecifierName(
+ TagType, Actions.getASTContext().getPrintingPolicy());
+  ConsumeAnnotationToken();
+  continue;
+}
+
 if (!Tok.is(tok::at)) {
   auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
 // Install the declarator into the current TagDecl.
Index: clang/lib/Basic/TokenKinds.cpp
===
--- clang/lib/Basic/TokenKinds.cpp
+++ clang/lib/Basic/TokenKinds.cpp
@@ -12,6 +12,7 @@
 
 #include "clang/Basic/TokenKinds.h"
 #include "llvm/Support/ErrorHandling.h"
+#include 
 using namespace clang;
 
 static const char * const TokNames[] = {
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -976,6 +976,8 @@
 def warn_pragma_invalid_argument : Warning<
   "unexpected argument '%0' to '#pragma %1'%select{|; expected %3}2">, InGroup;
 
+def err_pragma_misplaced_in_decl : Error<"this pragma cannot appear in %0 declaration">;
+
 // '#pragma clang section' related errors
 def err_pragma_expected_clang_section_name : Error<
   "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">;

[PATCH] D65406: [Parser] Change parameter type from int to enum

2019-08-01 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL367545: [Parser] Change parameter type from int to enum 
(authored by sepavloff, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D65406?vs=212187&id=212782#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D65406

Files:
  cfe/trunk/include/clang/Parse/Parser.h
  cfe/trunk/lib/Parse/ParseDecl.cpp
  cfe/trunk/lib/Parse/ParseDeclCXX.cpp
  cfe/trunk/lib/Parse/Parser.cpp


Index: cfe/trunk/include/clang/Parse/Parser.h
===
--- cfe/trunk/include/clang/Parse/Parser.h
+++ cfe/trunk/include/clang/Parse/Parser.h
@@ -972,7 +972,7 @@
   };
 
   /// Consume any extra semi-colons until the end of the line.
-  void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified);
+  void ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST T = TST_unspecified);
 
   /// Return false if the next token is an identifier. An 'expected identifier'
   /// error is emitted otherwise.
@@ -2160,7 +2160,7 @@
   const ParsedTemplateInfo &TemplateInfo,
   AccessSpecifier AS, DeclSpecContext DSC);
   void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl);
-  void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
+  void ParseStructUnionBody(SourceLocation StartLoc, DeclSpec::TST TagType,
 Decl *TagDecl);
 
   void ParseStructDeclaration(
Index: cfe/trunk/lib/Parse/Parser.cpp
===
--- cfe/trunk/lib/Parse/Parser.cpp
+++ cfe/trunk/lib/Parse/Parser.cpp
@@ -174,7 +174,7 @@
   return ExpectAndConsume(tok::semi, DiagID);
 }
 
-void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
+void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
   if (!Tok.is(tok::semi)) return;
 
   bool HadMultipleSemis = false;
@@ -202,7 +202,7 @@
 
   if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis)
 Diag(StartLoc, diag::ext_extra_semi)
-<< Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST,
+<< Kind << DeclSpec::getSpecifierName(TST,
 
Actions.getASTContext().getPrintingPolicy())
 << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
   else
Index: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
===
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp
@@ -4337,7 +4337,7 @@
   while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
 // __if_exists, __if_not_exists can nest.
 if (Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
-  ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType,
+  ParseMicrosoftIfExistsClassDeclaration(TagType,
  AccessAttrs, CurAS);
   continue;
 }
Index: cfe/trunk/lib/Parse/ParseDecl.cpp
===
--- cfe/trunk/lib/Parse/ParseDecl.cpp
+++ cfe/trunk/lib/Parse/ParseDecl.cpp
@@ -4098,7 +4098,7 @@
 /// [OBC]   '@' 'defs' '(' class-name ')'
 ///
 void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
-  unsigned TagType, Decl *TagDecl) {
+  DeclSpec::TST TagType, Decl *TagDecl) {
   PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
   "parsing struct/union body");
   assert(!getLangOpts().CPlusPlus && "C++ declarations not supported");


Index: cfe/trunk/include/clang/Parse/Parser.h
===
--- cfe/trunk/include/clang/Parse/Parser.h
+++ cfe/trunk/include/clang/Parse/Parser.h
@@ -972,7 +972,7 @@
   };
 
   /// Consume any extra semi-colons until the end of the line.
-  void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified);
+  void ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST T = TST_unspecified);
 
   /// Return false if the next token is an identifier. An 'expected identifier'
   /// error is emitted otherwise.
@@ -2160,7 +2160,7 @@
   const ParsedTemplateInfo &TemplateInfo,
   AccessSpecifier AS, DeclSpecContext DSC);
   void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl);
-  void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
+  void ParseStructUnionBody(SourceLocation StartLoc, DeclSpec::TST TagType,
 Decl *TagDecl);
 
   void ParseStructDeclaration(
Index: cfe/trunk/lib/Parse/Parser.cpp
===
--- cfe/trunk/lib/Parse/Parser.cpp
+++ cfe/trunk/lib/Parse/Parser.cpp
@@ -174,7 

[PATCH] D65405: [Parser] Use special definition for pragma annotations

2019-08-01 Thread Serge Pavlov 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 rL367575: [Parser] Use special definition for pragma 
annotations (authored by sepavloff, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D65405?vs=212186&id=212822#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D65405

Files:
  cfe/trunk/include/clang/Basic/TokenKinds.def
  cfe/trunk/include/clang/Basic/TokenKinds.h
  cfe/trunk/lib/Basic/TokenKinds.cpp

Index: cfe/trunk/lib/Basic/TokenKinds.cpp
===
--- cfe/trunk/lib/Basic/TokenKinds.cpp
+++ cfe/trunk/lib/Basic/TokenKinds.cpp
@@ -45,3 +45,13 @@
   }
   return nullptr;
 }
+
+bool tok::isPragmaAnnotation(TokenKind Kind) {
+  switch (Kind) {
+#define PRAGMA_ANNOTATION(X) case annot_ ## X: return true;
+#include "clang/Basic/TokenKinds.def"
+  default:
+break;
+  }
+  return false;
+}
Index: cfe/trunk/include/clang/Basic/TokenKinds.h
===
--- cfe/trunk/include/clang/Basic/TokenKinds.h
+++ cfe/trunk/include/clang/Basic/TokenKinds.h
@@ -98,6 +98,9 @@
   return false;
 }
 
+/// Return true if this is an annotation token representing a pragma.
+bool isPragmaAnnotation(TokenKind K);
+
 }  // end namespace tok
 }  // end namespace clang
 
Index: cfe/trunk/include/clang/Basic/TokenKinds.def
===
--- cfe/trunk/include/clang/Basic/TokenKinds.def
+++ cfe/trunk/include/clang/Basic/TokenKinds.def
@@ -68,6 +68,9 @@
 #ifndef ANNOTATION
 #define ANNOTATION(X) TOK(annot_ ## X)
 #endif
+#ifndef PRAGMA_ANNOTATION
+#define PRAGMA_ANNOTATION(X) ANNOTATION(X)
+#endif
 
 //===--===//
 // Preprocessor keywords.
@@ -729,103 +732,103 @@
 // Annotation for #pragma unused(...)
 // For each argument inside the parentheses the pragma handler will produce
 // one 'pragma_unused' annotation token followed by the argument token.
-ANNOTATION(pragma_unused)
+PRAGMA_ANNOTATION(pragma_unused)
 
 // Annotation for #pragma GCC visibility...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_vis)
+PRAGMA_ANNOTATION(pragma_vis)
 
 // Annotation for #pragma pack...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_pack)
+PRAGMA_ANNOTATION(pragma_pack)
 
 // Annotation for #pragma clang __debug parser_crash...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_parser_crash)
+PRAGMA_ANNOTATION(pragma_parser_crash)
 
 // Annotation for #pragma clang __debug captured...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_captured)
+PRAGMA_ANNOTATION(pragma_captured)
 
 // Annotation for #pragma clang __debug dump...
 // The lexer produces these so that the parser and semantic analysis can
 // look up and dump the operand.
-ANNOTATION(pragma_dump)
+PRAGMA_ANNOTATION(pragma_dump)
 
 // Annotation for #pragma ms_struct...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_msstruct)
+PRAGMA_ANNOTATION(pragma_msstruct)
 
 // Annotation for #pragma align...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_align)
+PRAGMA_ANNOTATION(pragma_align)
 
 // Annotation for #pragma weak id
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_weak)
+PRAGMA_ANNOTATION(pragma_weak)
 
 // Annotation for #pragma weak id = id
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_weakalias)
+PRAGMA_ANNOTATION(pragma_weakalias)
 
 // Annotation for #pragma redefine_extname...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_redefine_extname)
+PRAGMA_ANNOTATION(pragma_redefine_extname)
 
 // Annotation for #pragma STDC FP_CONTRACT...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_fp_contract)
+PRAGMA_ANNOTATION(pragma_fp_contract)
 
 // Annotation for #pragma STDC FENV_ACCESS
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_fenv_access)
+PRAGMA_ANNOTATION(pragma_fenv_access)
 
 // Annotation for #pragma pointers_to_members...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
-ANNOTATION(pragma_ms_pointers_to_members)
+PRAGMA_ANNOTATIO

[PATCH] D64932: [Parser] Emit descriptive diagnostic for misplaced pragma

2019-08-02 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 213023.
sepavloff added a comment.

Updated patch


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D64932

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/test/Parser/pragma-attribute-context.cpp
  clang/test/Parser/pragma-fp-contract.c
  clang/test/Parser/pragma-fp-contract.cpp

Index: clang/test/Parser/pragma-fp-contract.cpp
===
--- /dev/null
+++ clang/test/Parser/pragma-fp-contract.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f1(void) {
+  int x = 0;
+/* expected-error@+1 {{'#pragma fp_contract' can only appear at file scope or at the start of a compound statement}} */
+#pragma STDC FP_CONTRACT ON
+}
+
+void f2(void) {
+  #pragma STDC FP_CONTRACT OFF
+  #pragma STDC FP_CONTRACT ON
+}
+
+struct S1 {
+// expected-error@+1 {{this pragma cannot appear in struct declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f1;
+};
+
+union U1 {
+  float f1;
+  float f2;
+// expected-error@+1 {{this pragma cannot appear in union declaration}}
+#pragma STDC FP_CONTRACT ON
+};
+
+class C1 {
+  float f1;
+// expected-error@+1 {{this pragma cannot appear in class declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f2;
+};
Index: clang/test/Parser/pragma-fp-contract.c
===
--- clang/test/Parser/pragma-fp-contract.c
+++ clang/test/Parser/pragma-fp-contract.c
@@ -10,3 +10,16 @@
   #pragma STDC FP_CONTRACT OFF
   #pragma STDC FP_CONTRACT ON 
 }
+
+struct S1 {
+// expected-error@+1 {{this pragma cannot appear in struct declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f1;
+};
+
+union U1 {
+  float f1;
+  float f2;
+// expected-error@+1 {{this pragma cannot appear in union declaration}}
+#pragma STDC FP_CONTRACT ON
+};
Index: clang/test/Parser/pragma-attribute-context.cpp
===
--- clang/test/Parser/pragma-attribute-context.cpp
+++ clang/test/Parser/pragma-attribute-context.cpp
@@ -31,8 +31,7 @@
 
 struct InStruct {
   // FIXME: This asserts in Objective-C++!
-  // FIXME: This is a horrible diagnostic!
 #ifndef __OBJC__
-  BEGIN_PRAGMA // expected-error {{expected member name or ';' after declaration specifiers}}
+  BEGIN_PRAGMA // expected-error {{this pragma cannot appear in struct declaration}}
 #endif
 };
Index: clang/lib/Parse/ParseDeclCXX.cpp
===
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -3134,6 +3134,13 @@
   TagDecl);
 
   default:
+if (tok::isPragmaAnnotation(Tok.getKind())) {
+  Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+  << DeclSpec::getSpecifierName(TagType,
+   Actions.getASTContext().getPrintingPolicy());
+  ConsumeAnnotationToken();
+  return nullptr;
+}
 return ParseCXXClassMemberDeclaration(AS, AccessAttrs);
   }
 }
Index: clang/lib/Parse/ParseDecl.cpp
===
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -4148,6 +4148,14 @@
   continue;
 }
 
+if (tok::isPragmaAnnotation(Tok.getKind())) {
+  Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+  << DeclSpec::getSpecifierName(
+ TagType, Actions.getASTContext().getPrintingPolicy());
+  ConsumeAnnotationToken();
+  continue;
+}
+
 if (!Tok.is(tok::at)) {
   auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
 // Install the declarator into the current TagDecl.
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -976,6 +976,8 @@
 def warn_pragma_invalid_argument : Warning<
   "unexpected argument '%0' to '#pragma %1'%select{|; expected %3}2">, InGroup;
 
+def err_pragma_misplaced_in_decl : Error<"this pragma cannot appear in %0 declaration">;
+
 // '#pragma clang section' related errors
 def err_pragma_expected_clang_section_name : Error<
   "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D64932: [Parser] Emit descriptive diagnostic for misplaced pragma

2019-08-02 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked 2 inline comments as done.
sepavloff added inline comments.



Comment at: clang/lib/Basic/TokenKinds.cpp:15
 #include "llvm/Support/ErrorHandling.h"
+#include 
 using namespace clang;

rjmccall wrote:
> This is no longer necessary, right?
Sure, removed it.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D64932



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


[PATCH] D65670: Use switch instead of series of comparisons

2019-08-02 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: rjmccall, alexfh.
Herald added a project: clang.

This is style correction, no functional changes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D65670

Files:
  clang/include/clang/Basic/TokenKinds.h
  clang/lib/Basic/TokenKinds.cpp


Index: clang/lib/Basic/TokenKinds.cpp
===
--- clang/lib/Basic/TokenKinds.cpp
+++ clang/lib/Basic/TokenKinds.cpp
@@ -46,6 +46,16 @@
   return nullptr;
 }
 
+bool tok::isAnnotation(TokenKind Kind) {
+  switch (Kind) {
+#define ANNOTATION(X) case annot_ ## X: return true;
+#include "clang/Basic/TokenKinds.def"
+  default:
+break;
+  }
+  return false;
+}
+
 bool tok::isPragmaAnnotation(TokenKind Kind) {
   switch (Kind) {
 #define PRAGMA_ANNOTATION(X) case annot_ ## X: return true;
Index: clang/include/clang/Basic/TokenKinds.h
===
--- clang/include/clang/Basic/TokenKinds.h
+++ clang/include/clang/Basic/TokenKinds.h
@@ -90,13 +90,7 @@
 }
 
 /// Return true if this is any of tok::annot_* kinds.
-inline bool isAnnotation(TokenKind K) {
-#define ANNOTATION(NAME) \
-  if (K == tok::annot_##NAME) \
-return true;
-#include "clang/Basic/TokenKinds.def"
-  return false;
-}
+bool isAnnotation(TokenKind K);
 
 /// Return true if this is an annotation token representing a pragma.
 bool isPragmaAnnotation(TokenKind K);


Index: clang/lib/Basic/TokenKinds.cpp
===
--- clang/lib/Basic/TokenKinds.cpp
+++ clang/lib/Basic/TokenKinds.cpp
@@ -46,6 +46,16 @@
   return nullptr;
 }
 
+bool tok::isAnnotation(TokenKind Kind) {
+  switch (Kind) {
+#define ANNOTATION(X) case annot_ ## X: return true;
+#include "clang/Basic/TokenKinds.def"
+  default:
+break;
+  }
+  return false;
+}
+
 bool tok::isPragmaAnnotation(TokenKind Kind) {
   switch (Kind) {
 #define PRAGMA_ANNOTATION(X) case annot_ ## X: return true;
Index: clang/include/clang/Basic/TokenKinds.h
===
--- clang/include/clang/Basic/TokenKinds.h
+++ clang/include/clang/Basic/TokenKinds.h
@@ -90,13 +90,7 @@
 }
 
 /// Return true if this is any of tok::annot_* kinds.
-inline bool isAnnotation(TokenKind K) {
-#define ANNOTATION(NAME) \
-  if (K == tok::annot_##NAME) \
-return true;
-#include "clang/Basic/TokenKinds.def"
-  return false;
-}
+bool isAnnotation(TokenKind K);
 
 /// Return true if this is an annotation token representing a pragma.
 bool isPragmaAnnotation(TokenKind K);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D65405: [Parser] Use special definition for pragma annotations

2019-08-02 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

> LGTM, although I don't think it would be ridiculous to make this an inline 
> function definition like isAnnotation.

Thank you!
The fix for `isAnnotation` is D65670 .


Repository:
  rL LLVM

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

https://reviews.llvm.org/D65405



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


[PATCH] D65670: Use switch instead of series of comparisons

2019-08-03 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL367759: Use switch instead of series of comparisons 
(authored by sepavloff, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D65670?vs=213100&id=213192#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D65670

Files:
  cfe/trunk/include/clang/Basic/TokenKinds.h
  cfe/trunk/lib/Basic/TokenKinds.cpp


Index: cfe/trunk/include/clang/Basic/TokenKinds.h
===
--- cfe/trunk/include/clang/Basic/TokenKinds.h
+++ cfe/trunk/include/clang/Basic/TokenKinds.h
@@ -90,13 +90,7 @@
 }
 
 /// Return true if this is any of tok::annot_* kinds.
-inline bool isAnnotation(TokenKind K) {
-#define ANNOTATION(NAME) \
-  if (K == tok::annot_##NAME) \
-return true;
-#include "clang/Basic/TokenKinds.def"
-  return false;
-}
+bool isAnnotation(TokenKind K);
 
 /// Return true if this is an annotation token representing a pragma.
 bool isPragmaAnnotation(TokenKind K);
Index: cfe/trunk/lib/Basic/TokenKinds.cpp
===
--- cfe/trunk/lib/Basic/TokenKinds.cpp
+++ cfe/trunk/lib/Basic/TokenKinds.cpp
@@ -46,6 +46,16 @@
   return nullptr;
 }
 
+bool tok::isAnnotation(TokenKind Kind) {
+  switch (Kind) {
+#define ANNOTATION(X) case annot_ ## X: return true;
+#include "clang/Basic/TokenKinds.def"
+  default:
+break;
+  }
+  return false;
+}
+
 bool tok::isPragmaAnnotation(TokenKind Kind) {
   switch (Kind) {
 #define PRAGMA_ANNOTATION(X) case annot_ ## X: return true;


Index: cfe/trunk/include/clang/Basic/TokenKinds.h
===
--- cfe/trunk/include/clang/Basic/TokenKinds.h
+++ cfe/trunk/include/clang/Basic/TokenKinds.h
@@ -90,13 +90,7 @@
 }
 
 /// Return true if this is any of tok::annot_* kinds.
-inline bool isAnnotation(TokenKind K) {
-#define ANNOTATION(NAME) \
-  if (K == tok::annot_##NAME) \
-return true;
-#include "clang/Basic/TokenKinds.def"
-  return false;
-}
+bool isAnnotation(TokenKind K);
 
 /// Return true if this is an annotation token representing a pragma.
 bool isPragmaAnnotation(TokenKind K);
Index: cfe/trunk/lib/Basic/TokenKinds.cpp
===
--- cfe/trunk/lib/Basic/TokenKinds.cpp
+++ cfe/trunk/lib/Basic/TokenKinds.cpp
@@ -46,6 +46,16 @@
   return nullptr;
 }
 
+bool tok::isAnnotation(TokenKind Kind) {
+  switch (Kind) {
+#define ANNOTATION(X) case annot_ ## X: return true;
+#include "clang/Basic/TokenKinds.def"
+  default:
+break;
+  }
+  return false;
+}
+
 bool tok::isPragmaAnnotation(TokenKind Kind) {
   switch (Kind) {
 #define PRAGMA_ANNOTATION(X) case annot_ ## X: return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D64932: [Parser] Emit descriptive diagnostic for misplaced pragma

2019-08-04 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
sepavloff marked an inline comment as done.
Closed by commit rL367779: [Parser] Emit descriptive diagnostic for misplaced 
pragma (authored by sepavloff, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D64932?vs=213023&id=213239#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D64932

Files:
  cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
  cfe/trunk/lib/Parse/ParseDecl.cpp
  cfe/trunk/lib/Parse/ParseDeclCXX.cpp
  cfe/trunk/test/Parser/pragma-attribute-context.cpp
  cfe/trunk/test/Parser/pragma-fp-contract.c
  cfe/trunk/test/Parser/pragma-fp-contract.cpp

Index: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
===
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp
@@ -3134,6 +3134,13 @@
   TagDecl);
 
   default:
+if (tok::isPragmaAnnotation(Tok.getKind())) {
+  Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+  << DeclSpec::getSpecifierName(TagType,
+   Actions.getASTContext().getPrintingPolicy());
+  ConsumeAnnotationToken();
+  return nullptr;
+}
 return ParseCXXClassMemberDeclaration(AS, AccessAttrs);
   }
 }
Index: cfe/trunk/lib/Parse/ParseDecl.cpp
===
--- cfe/trunk/lib/Parse/ParseDecl.cpp
+++ cfe/trunk/lib/Parse/ParseDecl.cpp
@@ -4148,6 +4148,14 @@
   continue;
 }
 
+if (tok::isPragmaAnnotation(Tok.getKind())) {
+  Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+  << DeclSpec::getSpecifierName(
+ TagType, Actions.getASTContext().getPrintingPolicy());
+  ConsumeAnnotationToken();
+  continue;
+}
+
 if (!Tok.is(tok::at)) {
   auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
 // Install the declarator into the current TagDecl.
Index: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
===
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
@@ -974,6 +974,8 @@
 def warn_pragma_invalid_argument : Warning<
   "unexpected argument '%0' to '#pragma %1'%select{|; expected %3}2">, InGroup;
 
+def err_pragma_misplaced_in_decl : Error<"this pragma cannot appear in %0 declaration">;
+
 // '#pragma clang section' related errors
 def err_pragma_expected_clang_section_name : Error<
   "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">;
Index: cfe/trunk/test/Parser/pragma-fp-contract.c
===
--- cfe/trunk/test/Parser/pragma-fp-contract.c
+++ cfe/trunk/test/Parser/pragma-fp-contract.c
@@ -10,3 +10,16 @@
   #pragma STDC FP_CONTRACT OFF
   #pragma STDC FP_CONTRACT ON 
 }
+
+struct S1 {
+// expected-error@+1 {{this pragma cannot appear in struct declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f1;
+};
+
+union U1 {
+  float f1;
+  float f2;
+// expected-error@+1 {{this pragma cannot appear in union declaration}}
+#pragma STDC FP_CONTRACT ON
+};
Index: cfe/trunk/test/Parser/pragma-fp-contract.cpp
===
--- cfe/trunk/test/Parser/pragma-fp-contract.cpp
+++ cfe/trunk/test/Parser/pragma-fp-contract.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f1(void) {
+  int x = 0;
+/* expected-error@+1 {{'#pragma fp_contract' can only appear at file scope or at the start of a compound statement}} */
+#pragma STDC FP_CONTRACT ON
+}
+
+void f2(void) {
+  #pragma STDC FP_CONTRACT OFF
+  #pragma STDC FP_CONTRACT ON
+}
+
+struct S1 {
+// expected-error@+1 {{this pragma cannot appear in struct declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f1;
+};
+
+union U1 {
+  float f1;
+  float f2;
+// expected-error@+1 {{this pragma cannot appear in union declaration}}
+#pragma STDC FP_CONTRACT ON
+};
+
+class C1 {
+  float f1;
+// expected-error@+1 {{this pragma cannot appear in class declaration}}
+#pragma STDC FP_CONTRACT ON
+  float f2;
+};
Index: cfe/trunk/test/Parser/pragma-attribute-context.cpp
===
--- cfe/trunk/test/Parser/pragma-attribute-context.cpp
+++ cfe/trunk/test/Parser/pragma-attribute-context.cpp
@@ -31,8 +31,7 @@
 
 struct InStruct {
   // FIXME: This asserts in Objective-C++!
-  // FIXME: This is a horrible diagnostic!
 #ifndef __OBJC__
-  BEGIN_PRAGMA // expected-error {{expected member name or ';' after declaration specifiers}}
+  BEGIN_PRAGMA // expected-error {{this pragma cannot appear in struct declaration}}
 #endif
 };
___
c

[PATCH] D65994: Extended FPOptions with new attributes

2019-08-08 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: anemet, kpn, aaron.ballman, hfinkel, rsmith, 
rjmccall.
Herald added a project: clang.

This change added two new attributes, rounding mode and exception
behavior to the structure FPOptions. These attributes allow more
flexible treatment of specific floating point environment than it is
provided by fenv_access.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D65994

Files:
  clang/include/clang/AST/Stmt.h
  clang/include/clang/Basic/LangOptions.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/TreeTransform.h

Index: clang/lib/Sema/TreeTransform.h
===
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -9698,7 +9698,7 @@
   RHS.get() == E->getRHS())
 return E;
 
-  Sema::FPContractStateRAII FPContractState(getSema());
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
   getSema().FPFeatures = E->getFPFeatures();
 
   return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
@@ -10180,7 +10180,7 @@
   (E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
 return SemaRef.MaybeBindToTemporary(E);
 
-  Sema::FPContractStateRAII FPContractState(getSema());
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
   getSema().FPFeatures = E->getFPFeatures();
 
   return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
Index: clang/lib/Sema/SemaAttr.cpp
===
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -935,6 +935,14 @@
   }
 }
 
+void Sema::setRoundingMode(LangOptions::FPRoundingModeKind FPR) {
+  FPFeatures.setRoundingMode(FPR);
+}
+
+void Sema::setExceptionMode(LangOptions::FPExceptionModeKind FPE) {
+  FPFeatures.setExceptionMode(FPE);
+}
+
 void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) {
   switch (FPC) {
   case LangOptions::FEA_On:
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -998,9 +998,9 @@
 Tok.getLocation(),
 "in compound statement ('{}')");
 
-  // Record the state of the FP_CONTRACT pragma, restore on leaving the
+  // Record the state of the FPFeatures, restore on leaving the
   // compound statement.
-  Sema::FPContractStateRAII SaveFPContractState(Actions);
+  Sema::FPFeaturesStateRAII SaveFPContractState(Actions);
 
   InMessageExpressionRAIIObject InMessage(*this, false);
   BalancedDelimiterTracker T(*this, tok::l_brace);
Index: clang/include/clang/Sema/Sema.h
===
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1258,12 +1258,12 @@
   /// should not be used elsewhere.
   void EmitCurrentDiagnostic(unsigned DiagID);
 
-  /// Records and restores the FP_CONTRACT state on entry/exit of compound
+  /// Records and restores the FPFeatures state on entry/exit of compound
   /// statements.
-  class FPContractStateRAII {
+  class FPFeaturesStateRAII {
   public:
-FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {}
-~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; }
+FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {}
+~FPFeaturesStateRAII() { S.FPFeatures = OldFPFeaturesState; }
 
   private:
 Sema& S;
@@ -8759,6 +8759,12 @@
   /// \#pragma STDC FENV_ACCESS
   void ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC);
 
+  /// Called to set rounding mode for floating point operations.
+  void setRoundingMode(LangOptions::FPRoundingModeKind);
+
+  /// Called to set exception behavior for floating point operations.
+  void setExceptionMode(LangOptions::FPExceptionModeKind);
+
   /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to
   /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'.
   void AddAlignmentAttributesForRecord(RecordDecl *RD);
Index: clang/include/clang/Basic/LangOptions.h
===
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -178,6 +178,34 @@
 FEA_On
   };
 
+  // Values of the following enumerations correspond to metadata arguments
+  // specified for constrained floating-point intrinsics:
+  // http://llvm.org/docs/LangRef.html#constrained-floating-point-intrinsics.
+
+  /// Possible rounding modes.
+  enum FPRoundingModeKind {
+/// Rounding to nearest, corresponds to "round.tonearest".
+ToNearest,
+/// Rounding toward -Inf, corresponds to "round.downward".
+Downward,
+/// Rounding toward +Inf, corresponds to "round.upward".
+Upward,
+/// Rounding toward zero

  1   2   3   4   5   6   7   >