diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3bddfbaae6a..d6858d834f9 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -3035,6 +3035,20 @@ users are likely to want to adjust it, but if your code does heavy
 constexpr calculations you might want to experiment to find which
 value works best for you.
 
+@item -fconstexpr-fp-except
+@opindex fconstexpr-fp-except
+Annex F of the C standard specifies that IEC559 floating point
+exceptions encountered at compile time should not stop compilation.
+C++ compilers have historically not followed this guidance, instead
+treating floating point division by zero as non-constant even though
+it has a well defined value.  This flag tells the compiler to give
+Annex F priority over other rules saying that a particular operation
+is undefined.
+
+@smallexample
+constexpr float inf = 1./0.; // OK with -fconstexpr-fp-except
+@end smallexample
+
 @item -fconstexpr-loop-limit=@var{n}
 @opindex fconstexpr-loop-limit
 Set the maximum number of iterations for a loop in C++14 constexpr functions
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 4b8a094b206..5654f044ae4 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1615,6 +1615,10 @@ fconstexpr-cache-depth=
 C++ ObjC++ Joined RejectNegative UInteger Var(constexpr_cache_depth) Init(8)
 -fconstexpr-cache-depth=<number>	Specify maximum constexpr recursion cache depth.
 
+fconstexpr-fp-except
+C++ ObjC++ Var(flag_constexpr_fp_except) Init(0)
+Allow IEC559 floating point exceptions in constant expressions
+
 fconstexpr-loop-limit=
 C++ ObjC++ Joined RejectNegative UInteger Var(constexpr_loop_limit) Init(262144)
 -fconstexpr-loop-limit=<number>	Specify maximum constexpr loop iteration count.
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 56e9d399c0d..01bfe5df9b5 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -77,6 +77,7 @@ extern tree fold_build_call_array_loc (location_t, tree, tree, int, tree *);
 #define fold_build_call_array_initializer(T1,T2,N,T4)\
    fold_build_call_array_initializer_loc (UNKNOWN_LOCATION, T1, T2, N, T4)
 extern tree fold_build_call_array_initializer_loc (location_t, tree, tree, int, tree *);
+extern tree fold_binary_initializer_loc (location_t, tree_code, tree, tree, tree);
 extern tree get_array_ctor_element_at_index (tree, offset_int,
 					     unsigned * = NULL);
 extern bool fold_convertible_p (const_tree, const_tree);
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index d66a56583ae..b4b8a96c6af 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -3366,7 +3366,14 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
     }
 
   if (r == NULL_TREE)
-    r = fold_binary_loc (loc, code, type, lhs, rhs);
+    {
+      if (ctx->manifestly_const_eval
+	  && (flag_constexpr_fp_except
+	      || TREE_CODE (type) != REAL_TYPE))
+	r = fold_binary_initializer_loc (loc, code, type, lhs, rhs);
+      else
+	r = fold_binary_loc (loc, code, type, lhs, rhs);
+    }
 
   if (r == NULL_TREE
       && (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 90d82257ae7..0b9a42f764a 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -85,8 +85,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "gimple-range.h"
 
-/* Nonzero if we are folding constants inside an initializer; zero
-   otherwise.  */
+/* Nonzero if we are folding constants inside an initializer or a C++
+   manifestly-constant-evaluated context; zero otherwise.  */
 int folding_initializer = 0;
 
 /* The following constants represent a bit based encoding of GCC's
@@ -9924,8 +9924,15 @@ pointer_may_wrap_p (tree base, tree offset, poly_int64 bitpos)
 static int
 maybe_nonzero_address (tree decl)
 {
+  /* Normally, don't do anything for variables and functions before symtab is
+     built; it is quite possible that DECL will be declared weak later.
+     But if folding_initializer, we need a constant answer now, so create
+     the symtab entry and prevent later weak declaration.  */
   if (DECL_P (decl) && decl_in_symtab_p (decl))
-    if (struct symtab_node *symbol = symtab_node::get_create (decl))
+    if (struct symtab_node *symbol
+	= (folding_initializer
+	   ? symtab_node::get_create (decl)
+	   : symtab_node::get (decl)))
       return symbol->nonzero_address ();
 
   /* Function local objects are never NULL.  */
@@ -13991,6 +13998,19 @@ fold_build_call_array_initializer_loc (location_t loc, tree type, tree fn,
   return result;
 }
 
+tree
+fold_binary_initializer_loc (location_t loc, tree_code code, tree type,
+			     tree lhs, tree rhs)
+{
+  tree result;
+  START_FOLD_INIT;
+
+  result = fold_binary_loc (loc, code, type, lhs, rhs);
+
+  END_FOLD_INIT;
+  return result;
+}
+
 #undef START_FOLD_INIT
 #undef END_FOLD_INIT
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-fp-except1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-fp-except1.C
new file mode 100644
index 00000000000..3887a5ba743
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-fp-except1.C
@@ -0,0 +1,4 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -fconstexpr-fp-except }
+
+constexpr double inf = 1./0.;
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if36.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if36.C
new file mode 100644
index 00000000000..4a1b134cc19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if36.C
@@ -0,0 +1,19 @@
+// PR c++/103310
+// Test that only manifestly-constant-evaluated comparisons lock a symbol's
+// weakness.
+
+// { dg-do compile { target c++17 } }
+
+extern void weakfn1 (void);
+extern void weakfn2 (void);
+
+void call_weakfn (void)
+{
+  if (weakfn1)
+    weakfn1 ();
+  if constexpr (weakfn2)
+    weakfn2 ();
+}
+
+extern void weakfn1 (void)  __attribute__((weak));
+extern void weakfn2 (void)  __attribute__((weak)); // { dg-error "declared weak after being used" }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/nonzero-1.c b/gcc/testsuite/gcc.dg/tree-ssa/nonzero-1.c
index c9d438e9374..aa21b71c730 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/nonzero-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/nonzero-1.c
@@ -1,12 +1,13 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdelete-null-pointer-checks -fdump-tree-optimized" } */
 /* { dg-require-weak "" } */
 
 /* { dg-skip-if "" keeps_null_pointer_checks } */
-extern int a; /* { dg-error "declared weak after being used" } */
+extern int a;
 int
 t()
 {
+  /* { dg-final { scan-tree-dump "&a != 0" "optimized" } } */
   return &a!=0;
 }
 extern int a __attribute__ ((weak));
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/nonzero-1a.c b/gcc/testsuite/gcc.dg/tree-ssa/nonzero-1a.c
new file mode 100644
index 00000000000..3d1eb97f151
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/nonzero-1a.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdelete-null-pointer-checks -fdump-tree-optimized" } */
+
+/* { dg-skip-if "" keeps_null_pointer_checks } */
+extern int a;
+int
+t()
+{
+  /* { dg-final { scan-tree-dump-not "&a != 0" "optimized" } } */
+  return &a!=0;
+}
diff --git a/gcc/varasm.c b/gcc/varasm.c
index d6031d6f1a2..9315e2c6936 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -5869,7 +5869,7 @@ mark_weak (tree decl)
 
   struct symtab_node *n = symtab_node::get (decl);
   if (n && n->refuse_visibility_changes)
-    error ("%+qD declared weak after being used", decl);
+    error ("%qD declared weak after being used", decl);
   DECL_WEAK (decl) = 1;
 
   if (DECL_RTL_SET_P (decl)
