[PATCH] D51855: [constexpr] Fix ICE when memcpy() is given a pointer to an incomplete array

2018-09-10 Thread Petr Pavlu via Phabricator via cfe-commits
petpav01 created this revision.
petpav01 added a reviewer: rsmith.
Herald added a reviewer: javed.absar.
Herald added subscribers: cfe-commits, kristof.beyls.

Trying to compile the following example results in a clang crash:

  $ cat char.c
  void *memcpy(void *, const void *, unsigned int);
  extern char array2[];
  extern char array[];
  void test(void) { memcpy(&array, &array2, 9 * sizeof(char)); }
  
  $ ./llvm/build/bin/clang -target armv8a-none-eabi -c char.c
  clang-8: /work/llvm/lib/Support/APInt.cpp:1785: static void 
llvm::APInt::udivrem(const llvm::APInt&, uint64_t, llvm::APInt&, uint64_t&): 
Assertion `RHS != 0 && "Divide by zero?"' failed.
  [...]

The problem occurs since rC338941 . The 
change added support for constant evaluation of `__builtin_memcpy/memmove()` 
but it does not always cope well with incomplete types.

The AST for the `memcpy()` call looks as follows:

  CallExpr 0x7416d0 'void *'
  |-ImplicitCastExpr 0x7416b8 'void *(*)(void *, const void *, unsigned int)' 

  | `-DeclRefExpr 0x741518 'void *(void *, const void *, unsigned int)' 
Function 0x741198 'memcpy' 'void *(void *, const void *, unsigned int)'
  |-ImplicitCastExpr 0x741710 'void *' 
  | `-UnaryOperator 0x741598 'char (*)[]' prefix '&' cannot overflow
  |   `-DeclRefExpr 0x741540 'char []' lvalue Var 0x741358 'array' 'char []'
  |-ImplicitCastExpr 0x741728 'const void *' 
  | `-UnaryOperator 0x7415e0 'char (*)[]' prefix '&' cannot overflow
  |   `-DeclRefExpr 0x7415b8 'char []' lvalue Var 0x741298 'array2' 'char []'
  `-BinaryOperator 0x741668 'unsigned int' '*'
|-ImplicitCastExpr 0x741650 'unsigned int' 
| `-IntegerLiteral 0x741600 'int' 9
`-UnaryExprOrTypeTraitExpr 0x741630 'unsigned int' sizeof 'char'

The following happens in `PointerExprEvaluator::VisitBuiltinCallExpr()`, label 
`Builtin::BI__builtin_memcpy`:

- Types `T` and `SrcT` are determined as:

  IncompleteArrayType 0x741250 'char []'
  `-BuiltinType 0x6ff430 'char'

- Method `ASTContext::getTypeSizeInChars()` is called to obtain size of type 
`T`. It returns 0 because the type is incomplete. The result is stored in 
variable `TSize`.
- Following call to `llvm::APInt::udivrem(OrigN, TSize, N, Remainder)` fails 
because it attempts a divide by zero.

The proposed patch fixes the problem by adding a check that no incomplete type 
is getting copied prior to the call to `ASTContext::getTypeSizeInChars()`.


Repository:
  rC Clang

https://reviews.llvm.org/D51855

Files:
  include/clang/Basic/DiagnosticASTKinds.td
  lib/AST/ExprConstant.cpp
  test/CodeGen/builtin-memfns.c
  test/SemaCXX/constexpr-string.cpp


Index: test/SemaCXX/constexpr-string.cpp
===
--- test/SemaCXX/constexpr-string.cpp
+++ test/SemaCXX/constexpr-string.cpp
@@ -370,4 +370,31 @@
   // designators until we have a long enough matching size, if both designators
   // point to the start of their respective final elements.
   static_assert(test_derived_to_base(2) == 3434); // expected-error 
{{constant}} expected-note {{in call}}
+
+  // Check that when address-of an array is passed to a tested function the
+  // array can be fully copied.
+  constexpr int test_address_of_const_array_type() {
+int arr[4] = {1, 2, 3, 4};
+__builtin_memmove(&arr, &arr, sizeof(arr));
+return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_address_of_const_array_type() == 1234);
+
+  // Check that an incomplete array is rejected.
+  constexpr int test_incomplete_array_type() { // expected-error {{never 
produces a constant}}
+extern int arr[];
+__builtin_memmove(arr, arr, 4 * sizeof(arr[0]));
+// expected-note@-1 2{{'memmove' not supported: source is not a contiguous 
array of at least 4 elements of type 'int'}}
+return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_incomplete_array_type() == 1234); // expected-error 
{{constant}} expected-note {{in call}}
+
+  // Check that a pointer to an incomplete array is rejected.
+  constexpr int test_address_of_incomplete_array_type() { // expected-error 
{{never produces a constant}}
+extern int arr[];
+__builtin_memmove(&arr, &arr, 4 * sizeof(arr[0]));
+// expected-note@-1 2{{cannot constant evaluate 'memmove' between objects 
of incomplete type 'int []'}}
+return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_address_of_incomplete_array_type() == 1234); // 
expected-error {{constant}} expected-note {{in call}}
 }
Index: test/CodeGen/builtin-memfns.c
===
--- test/CodeGen/builtin-memfns.c
+++ test/CodeGen/builtin-memfns.c
@@ -111,3 +111,10 @@
   memcpy(&d, (char *)&e.a, sizeof(e));
 }
 
+// CHECK-LABEL: @test12
+extern char dest_array[];
+extern char src_array[];
+void test12() {
+  // CHECK: call void @llvm.memcpy{{.*}}(
+  memcpy(&dest_array, &dest_array, 2);

[PATCH] D51855: [constexpr] Fix ICE when memcpy() is given a pointer to an incomplete array

2018-09-19 Thread Petr Pavlu via Phabricator via cfe-commits
petpav01 updated this revision to Diff 166073.
petpav01 added a comment.

Thanks for having a look at this patch. Updated version addresses the review 
comments.


https://reviews.llvm.org/D51855

Files:
  include/clang/Basic/DiagnosticASTKinds.td
  lib/AST/ExprConstant.cpp
  test/CodeGen/builtin-memfns.c
  test/SemaCXX/constexpr-string.cpp


Index: test/SemaCXX/constexpr-string.cpp
===
--- test/SemaCXX/constexpr-string.cpp
+++ test/SemaCXX/constexpr-string.cpp
@@ -387,4 +387,41 @@
   // designators until we have a long enough matching size, if both designators
   // point to the start of their respective final elements.
   static_assert(test_derived_to_base(2) == 3434); // expected-error 
{{constant}} expected-note {{in call}}
+
+  // Check that when address-of an array is passed to a tested function the
+  // array can be fully copied.
+  constexpr int test_address_of_const_array_type() {
+int arr[4] = {1, 2, 3, 4};
+__builtin_memmove(&arr, &arr, sizeof(arr));
+return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_address_of_const_array_type() == 1234);
+
+  // Check that an incomplete array is rejected.
+  constexpr int test_incomplete_array_type() { // expected-error {{never 
produces a constant}}
+extern int arr[];
+__builtin_memmove(arr, arr, 4 * sizeof(arr[0]));
+// expected-note@-1 2{{'memmove' not supported: source is not a contiguous 
array of at least 4 elements of type 'int'}}
+return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_incomplete_array_type() == 1234); // expected-error 
{{constant}} expected-note {{in call}}
+
+  // Check that a pointer to an incomplete array is rejected.
+  constexpr int test_address_of_incomplete_array_type() { // expected-error 
{{never produces a constant}}
+extern int arr[];
+__builtin_memmove(&arr, &arr, 4 * sizeof(arr[0]));
+// expected-note@-1 2{{cannot constant evaluate 'memmove' between objects 
of incomplete type 'int []'}}
+return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_address_of_incomplete_array_type() == 1234); // 
expected-error {{constant}} expected-note {{in call}}
+
+  // Check that a pointer to an incomplete struct is rejected.
+  constexpr bool test_address_of_incomplete_struct_type() { // expected-error 
{{never produces a constant}}
+struct Incomplete;
+extern Incomplete x, y;
+__builtin_memcpy(&x, &x, 4);
+// expected-note@-1 2{{cannot constant evaluate 'memcpy' between objects 
of incomplete type 'Incomplete'}}
+return true;
+  }
+  static_assert(test_address_of_incomplete_struct_type()); // expected-error 
{{constant}} expected-note {{in call}}
 }
Index: test/CodeGen/builtin-memfns.c
===
--- test/CodeGen/builtin-memfns.c
+++ test/CodeGen/builtin-memfns.c
@@ -111,3 +111,10 @@
   memcpy(&d, (char *)&e.a, sizeof(e));
 }
 
+// CHECK-LABEL: @test12
+extern char dest_array[];
+extern char src_array[];
+void test12() {
+  // CHECK: call void @llvm.memcpy{{.*}}(
+  memcpy(&dest_array, &dest_array, 2);
+}
Index: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -6232,6 +6232,10 @@
   Info.FFDiag(E, diag::note_constexpr_memcpy_type_pun) << Move << SrcT << 
T;
   return false;
 }
+if (T->isIncompleteType()) {
+  Info.FFDiag(E, diag::note_constexpr_memcpy_incomplete_type) << Move << T;
+  return false;
+}
 if (!T.isTriviallyCopyableType(Info.Ctx)) {
   Info.FFDiag(E, diag::note_constexpr_memcpy_nontrivial) << Move << T;
   return false;
Index: include/clang/Basic/DiagnosticASTKinds.td
===
--- include/clang/Basic/DiagnosticASTKinds.td
+++ include/clang/Basic/DiagnosticASTKinds.td
@@ -173,6 +173,9 @@
 def note_constexpr_memcpy_nontrivial : Note<
   "cannot constant evaluate '%select{memcpy|memmove}0' between objects of "
   "non-trivially-copyable type %1">;
+def note_constexpr_memcpy_incomplete_type : Note<
+  "cannot constant evaluate '%select{memcpy|memmove}0' between objects of "
+  "incomplete type %1">;
 def note_constexpr_memcpy_overlap : Note<
   "'%select{memcpy|wmemcpy}0' between overlapping memory regions">;
 def note_constexpr_memcpy_unsupported : Note<


Index: test/SemaCXX/constexpr-string.cpp
===
--- test/SemaCXX/constexpr-string.cpp
+++ test/SemaCXX/constexpr-string.cpp
@@ -387,4 +387,41 @@
   // designators until we have a long enough matching size, if both designators
   // point to the start of their respective final elements.
   static_assert(test_derived_to_base(2) == 3434); // expected-error {{constant}} expected-note {{in call}}
+
+  // Check that when address-of an array

[PATCH] D51855: [constexpr] Fix ICE when memcpy() is given a pointer to an incomplete array

2018-10-04 Thread Petr Pavlu via Phabricator via cfe-commits
petpav01 added a comment.

No worries, thanks.


https://reviews.llvm.org/D51855



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


[PATCH] D45807: [libclang] Fix test LibclangReparseTest.FileName when TMPDIR is set to a symbolic link

2018-04-19 Thread Petr Pavlu via Phabricator via cfe-commits
petpav01 created this revision.
petpav01 added reviewers: MaskRay, jbcoe.
Herald added a subscriber: cfe-commits.

Commit r329515 
 recently 
added new test `LibclangReparseTest.FileName`. This test fails in an 
environment which has `TMPDIR` set to a symbolic link that points to an actual 
directory.

Example:

  build$ ln -s /tmp mytmp
  build$ TMPDIR=$PWD/mytmp ./tools/clang/unittests/libclang/libclangTests
  [...]
  [--] 5 tests from LibclangReparseTest
  [ RUN  ] LibclangReparseTest.FileName
  .../tools/clang/unittests/libclang/LibclangTest.cpp:497: Failure
  Value of: strstr(clang_getCString(cxname), CppName.c_str())
Actual: false
  Expected: true
  [  FAILED  ] LibclangReparseTest.FileName (10 ms)
  [...]

`CppName` is the original path in form `$tmpdir/libclang-test-xx/main.cpp`. 
Value `cxname` is obtained through `clang_File_tryGetRealPathName()` which 
gives the real path with the symlink resolved. The test fails because these two 
paths do not match.

The proposed patch addresses the problem by checking only that the value 
returned by `clang_File_tryGetRealPathName()` ends with "main.cpp".

Additionally, the patch makes the previous assertion in the test that checks 
result of `clang_getFileName()` stricter. It newly verifies that the name 
returned by the function is exactly same as what was given to 
`clang_parseTranslationUnit()`/`clang_getFile()`.


Repository:
  rC Clang

https://reviews.llvm.org/D45807

Files:
  unittests/libclang/LibclangTest.cpp


Index: unittests/libclang/LibclangTest.cpp
===
--- unittests/libclang/LibclangTest.cpp
+++ unittests/libclang/LibclangTest.cpp
@@ -8,6 +8,7 @@
 
//===--===//
 
 #include "clang-c/Index.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
@@ -490,11 +491,11 @@
   CXFile cxf = clang_getFile(ClangTU, CppName.c_str());
 
   CXString cxname = clang_getFileName(cxf);
-  ASSERT_TRUE(strstr(clang_getCString(cxname), CppName.c_str()));
+  ASSERT_STREQ(clang_getCString(cxname), CppName.c_str());
   clang_disposeString(cxname);
 
   cxname = clang_File_tryGetRealPathName(cxf);
-  ASSERT_TRUE(strstr(clang_getCString(cxname), CppName.c_str()));
+  ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).endswith("main.cpp"));
   clang_disposeString(cxname);
 }
 


Index: unittests/libclang/LibclangTest.cpp
===
--- unittests/libclang/LibclangTest.cpp
+++ unittests/libclang/LibclangTest.cpp
@@ -8,6 +8,7 @@
 //===--===//
 
 #include "clang-c/Index.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
@@ -490,11 +491,11 @@
   CXFile cxf = clang_getFile(ClangTU, CppName.c_str());
 
   CXString cxname = clang_getFileName(cxf);
-  ASSERT_TRUE(strstr(clang_getCString(cxname), CppName.c_str()));
+  ASSERT_STREQ(clang_getCString(cxname), CppName.c_str());
   clang_disposeString(cxname);
 
   cxname = clang_File_tryGetRealPathName(cxf);
-  ASSERT_TRUE(strstr(clang_getCString(cxname), CppName.c_str()));
+  ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).endswith("main.cpp"));
   clang_disposeString(cxname);
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48916: Fix setting of empty implicit-section-name attribute for functions affected by '#pragma clang section'

2018-07-04 Thread Petr Pavlu via Phabricator via cfe-commits
petpav01 created this revision.
petpav01 added reviewers: javed.absar, chill, rnk.
Herald added subscribers: cfe-commits, kristof.beyls.

Code in `CodeGenModule::SetFunctionAttributes()` can set an empty attribute 
`implicit-section-name` on a function that is affected by `#pragma clang 
text="section"`. This is incorrect because the attribute should contain a valid 
section name. If the function additionally also uses 
`__attribute__((section("section")))` then this results in emitting the 
function in a section with an empty name.

Example:

  $ cat repr.c
  #pragma clang section text=".text_pragma"
  void f(void) __attribute__((section(".text_attr")));
  void f(void) {}
  $ clang -target arm-none-eabi -march=armv7-a -c repr.c
  $ llvm-objdump -h repr.o
  
  repr.o: file format ELF32-arm-little
  
  Sections:
  Idx Name  Size  Address  Type
0    
1 .strtab   005d 
2 .text   TEXT
3   0004  TEXT
4 .ARM.exidx0008 
5 .rel.ARM.exidx 0008 
6 .comment  00b2 
7 .note.GNU-stack  
8 .ARM.attributes 003a 
9 .symtab   0050 

Section with index 3 contains the code for function `f()`. The name of the 
section should be `.text_attr` but is instead empty.

The following happens in this example:

- `CodeGenModule::EmitGlobalFunctionDefinition()` is called to emit IR for 
`f()`. It invokes `GetAddrOfFunction()` -> `GetOrCreateLLVMFunction()` -> 
`SetFunctionAttributes()`. The last method notices that the `FunctionDecl` has 
the `PragmaClangTextSectionAttr` attribute and wrongly sets empty 
`implicit-section-name` attribute on the resulting `llvm::Function`.
- `EmitGlobalFunctionDefinition()` calls `setNonAliasAttributes()` which 
normally also sets the `implicit-section-name` attribute but because the `Decl` 
has `SectionAttr` it gets skipped.

The patch fixes the issue by removing the problematic code that sets empty 
`implicit-section-name` from `CodeGenModule::SetFunctionAttributes()`. The idea 
is that it is sufficient to set this attribute only from 
`setNonAliasAttributes()` when a function is emitted.


Repository:
  rC Clang

https://reviews.llvm.org/D48916

Files:
  lib/CodeGen/CodeGenModule.cpp
  test/CodeGen/clang-sections-attribute.c


Index: test/CodeGen/clang-sections-attribute.c
===
--- /dev/null
+++ test/CodeGen/clang-sections-attribute.c
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s
+
+// Test interaction between __attribute__((section())) and '#pragma clang
+// section' directives. The attribute should always have higher priority than
+// the pragma.
+
+// Text tests.
+#pragma clang section text=".ext_fun_pragma"
+void ext_fun(void) __attribute__((section(".ext_fun_attr")));
+void ext_fun(void) {}
+#pragma clang section text=""
+
+void ext_fun2(void) __attribute__((section(".ext_fun2_attr")));
+#pragma clang section text=".ext_fun2_pragma"
+void ext_fun2(void) {}
+#pragma clang section text=""
+
+#pragma clang section text=".int_fun_pragma"
+static void int_fun(void) __attribute__((section(".int_fun_attr"), used));
+static void int_fun(void) {}
+#pragma clang section text=""
+
+static void int_fun2(void) __attribute__((section(".int_fun2_attr"), used));
+#pragma clang section text=".int_fun2_pragma"
+static void int_fun2(void) {}
+#pragma clang section text=""
+
+// Rodata tests.
+#pragma clang section rodata=".ext_const_pragma"
+__attribute__((section(".ext_const_attr")))
+const int ext_const = 1;
+#pragma clang section rodata=""
+
+#pragma clang section rodata=".int_const_pragma"
+__attribute__((section(".int_const_attr"), used))
+static const int int_const = 1;
+#pragma clang section rodata=""
+
+// Data tests.
+#pragma clang section data=".ext_var_pragma"
+__attribute__((section(".ext_var_attr")))
+int ext_var = 1;
+#pragma clang section data=""
+
+#pragma clang section data=".int_var_pragma"
+__attribute__((section(".int_var_attr"), used))
+static int int_var = 1;
+#pragma clang section data=""
+
+// Bss tests.
+#pragma clang section bss=".ext_zvar_pragma"
+__attribute__((section(".ext_zvar_attr")))
+int ext_zvar;
+#pragma clang section bss=""
+
+#pragma clang section bss=".int_zvar_pragma"
+__attribute__((section(".int_zvar_attr"), used))
+static int int_zvar;
+#pragma clang section bss=""
+
+// CHECK: @ext_const = constant i32 1, section ".ext_const_attr", align 4{{$}}
+// CHECK: @int_const = internal constant i32 1, section ".int_const_attr", 
align 4{{$}}
+// CHECK: @ext_var = global i32 1, section ".ext_var_attr", align 4{{$}}
+// CHECK: @int_var = internal global i32 1, section ".int_var_attr", align 
4{{$}}
+// CHECK: @ext_zvar = global i32 0, section ".ext_zvar_attr", 

[PATCH] D48916: Fix setting of empty implicit-section-name attribute for functions affected by '#pragma clang section'

2018-07-04 Thread Petr Pavlu via Phabricator via cfe-commits
petpav01 added inline comments.



Comment at: test/CodeGen/clang-sections-attribute.c:1
+// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s
+

chill wrote:
> Isn't it possible for the test to fail if the Arm target is not configured?
I think it should not be necessary to add a REQUIRES line because the test 
emits and checks only LLVM IR but no target codegen is done. An experiment 
without having the ARM target configured shows that the test still works in 
such a setting. Note also that the two already present tests for `#pragma clang 
section` (`clang-sections.cpp` and `clang-sections-tentative.c`) have a similar 
header as this new test as well.


Repository:
  rC Clang

https://reviews.llvm.org/D48916



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


[PATCH] D13289: [libc++] Provide additional templates for valarray transcendentals that satisfy the standard synopsis

2017-01-29 Thread Petr Pavlu via Phabricator via cfe-commits
petpav01 updated this revision to Diff 86217.
petpav01 added a comment.

Patch rebased.


https://reviews.llvm.org/D13289

Files:
  include/valarray
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/abs_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/acos_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/asin_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/atan2_valarray_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/atan2_valarray_value.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/atan2_value_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/atan_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/cos_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/cosh_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/exp_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/log10_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/log_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/pow_valarray_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/pow_valarray_value.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/pow_value_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/sin_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/sinh_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/sqrt_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/tan_valarray.pass.cpp
  
test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/tanh_valarray.pass.cpp

Index: test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/tanh_valarray.pass.cpp
===
--- test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/tanh_valarray.pass.cpp
+++ test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/tanh_valarray.pass.cpp
@@ -34,19 +34,36 @@
 
 int main()
 {
+typedef double T;
+T a1[] = {-.9, -.5, 0., .5, .75};
+T a3[] = {-7.1629787019902447e-01,
+  -4.6211715726000974e-01,
+   0.e+00,
+   4.6211715726000974e-01,
+   6.3514895238728730e-01};
+const unsigned N = sizeof(a1)/sizeof(a1[0]);
 {
-typedef double T;
-T a1[] = {-.9, -.5, 0., .5, .75};
-T a3[] = {-7.1629787019902447e-01,
-  -4.6211715726000974e-01,
-   0.e+00,
-   4.6211715726000974e-01,
-   6.3514895238728730e-01};
-const unsigned N = sizeof(a1)/sizeof(a1[0]);
+// tanh(valarray&)
 std::valarray v1(a1, N);
 std::valarray v3 = tanh(v1);
 assert(v3.size() == v1.size());
 for (std::size_t i = 0; i < v3.size(); ++i)
 assert(is_about(v3[i], a3[i], 10));
 }
+{
+// tanh(__val_expr&)
+std::valarray v1(a1, N);
+std::valarray v3 = tanh(v1 + 0.0);
+assert(v3.size() == v1.size());
+for (int i = 0; i < v3.size(); ++i)
+assert(is_about(v3[i], a3[i], 10));
+}
+{
+// tanh()
+std::valarray v1(a1, N);
+std::valarray v3 = std::tanh(v1);
+assert(v3.size() == v1.size());
+for (int i = 0; i < v3.size(); ++i)
+assert(is_about(v3[i], a3[i], 10));
+}
 }
Index: test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/tan_valarray.pass.cpp
===
--- test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/tan_valarray.pass.cpp
+++ test/std/numerics/numarray/valarray.nonmembers/valarray.transcend/tan_valarray.pass.cpp
@@ -34,19 +34,36 @@
 
 int main()
 {
+typedef double T;
+T a1[] = {-.9, -.5, 0., .5, .75};
+T a3[] = {-1.2601582175503390e+00,
+  -5.4630248984379048e-01,
+   0.e+00,
+   5.4630248984379048e-01,
+   9.3159645994407259e-01};
+const unsigned N = sizeof(a1)/sizeof(a1[0]);
 {
-typedef double T;
-T a1[] = {-.9, -.5, 0., .5, .75};
-T a3[] = {-1.2601582175503390e+00,
-  -5.4630248984379048e-01,
-   0.e+00,
-   5.4630248984379048e-01,
-   9.3159645994407259e-01};
-const unsigned N = sizeof(a1)/sizeof(a1[0]);
+// tan(valarray&)
 std::valarray v1(a1, N);
 std::valarray v3 = tan(v1);
 assert(v3