aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorEdward Smith-Rowland <3dw4rd@verizon.net>2014-11-10 15:53:12 +0000
committerEdward Smith-Rowland <emsr@gcc.gnu.org>2014-11-10 15:53:12 +0000
commit42fd12b1e7fc50183bcf62861aae81301a9efbcf (patch)
treecdf2ab35de7a1da1bcda63af97f127dea644c2ce /gcc
parent6d64f20c8d50ce563f7b709593ac1229f2146c61 (diff)
downloadgcc-42fd12b1e7fc50183bcf62861aae81301a9efbcf.zip
gcc-42fd12b1e7fc50183bcf62861aae81301a9efbcf.tar.gz
gcc-42fd12b1e7fc50183bcf62861aae81301a9efbcf.tar.bz2
cpplib.h (cpp_callbacks): Add has_attribute.
libcpp: 2014-11-10 Edward Smith-Rowland <3dw4rd@verizon.net> * include/cpplib.h (cpp_callbacks): Add has_attribute. * internal.h (lexer_state): Add in__has_attribute__. * directives.c (lex_macro_node): Prevent use of __has_attribute__ as a macro. * expr.c (parse_has_attribute): New function; (eval_token): Look for __has_attribute__ and route to parse_has_attribute. * identifiers.c (_cpp_init_hashtable): Initialize n__has_attribute__. * pch.c (cpp_read_state): Initialize n__has_attribute__. * traditional.c (enum ls): Add ls_has_attribute, ls_has_attribute_close; (_cpp_scan_out_logical_line): Attend to __has_attribute__. gcc/c-family: 2014-11-10 Edward Smith-Rowland <3dw4rd@verizon.net> * c-cppbuiltin.c (__has_attribute, __has_cpp_attribute): New macros; (__cpp_rtti, __cpp_exceptions): New macros for C++98; (__cpp_range_based_for, __cpp_initializer_lists, __cpp_delegating_constructors, __cpp_nsdmi, __cpp_inheriting_constructors, __cpp_ref_qualifiers): New macros for C++11; (__cpp_attribute_deprecated): Remove in favor of __has_cpp_attribute. * c-lex.c (cb_has_attribute): New callback CPP function; (init_c_lex): Set has_attribute callback. gcc/testsuite: 2014-11-10 Edward Smith-Rowland <3dw4rd@verizon.net> * g++.dg/cpp1y/feat-cxx11.C: Test new feature macros for C++98 and C++11; Test existence of __has_cpp_attribute; Test C++11 attributes. * g++.dg/cpp1y/feat-cxx11-neg.C: Ditto. * g++.dg/cpp1y/feat-cxx14.C: Ditto and test for C++14 attributes. * g++.dg/cpp1y/feat-cxx98.C: Test new feature macros for C++98. * g++.dg/cpp1y/feat-cxx98-neg.C: Ditto. * g++.dg/cpp1y/feat-neg.C: Test that __cpp_rtti, _cpp_exceptions will be undefined for -fno-rtti -fno-exceptions. From-SVN: r217292
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c-family/ChangeLog12
-rw-r--r--gcc/c-family/c-cppbuiltin.c25
-rw-r--r--gcc/c-family/c-lex.c73
-rw-r--r--gcc/testsuite/ChangeLog12
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C87
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C87
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C50
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/feat-cxx98.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/feat-neg.C12
10 files changed, 362 insertions, 20 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 861ba07..f2295ed 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,15 @@
+2014-11-10 Edward Smith-Rowland <3dw4rd@verizon.net>
+
+ * c-cppbuiltin.c (__has_attribute, __has_cpp_attribute): New macros;
+ (__cpp_rtti, __cpp_exceptions): New macros for C++98;
+ (__cpp_range_based_for, __cpp_initializer_lists,
+ __cpp_delegating_constructors, __cpp_nsdmi,
+ __cpp_inheriting_constructors, __cpp_ref_qualifiers): New macros
+ for C++11; (__cpp_attribute_deprecated): Remove in favor of
+ __has_cpp_attribute.
+ * c-lex.c (cb_has_attribute): New callback CPP function;
+ (init_c_lex): Set has_attribute callback.
+
2014-11-04 Richard Biener <rguenther@suse.de>
* c-common.c (shorten_compare): Do not shorten mixed
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 26fabc2..a4ed5c6 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -790,11 +790,16 @@ c_cpp_builtins (cpp_reader *pfile)
c_stddef_cpp_builtins ();
/* Set include test macros for all C/C++ (not for just C++11 etc.)
- the builtins __has_include__ and __has_include_next__ are defined
+ The builtins __has_include__ and __has_include_next__ are defined
in libcpp. */
cpp_define (pfile, "__has_include(STR)=__has_include__(STR)");
cpp_define (pfile, "__has_include_next(STR)=__has_include_next__(STR)");
+ /* Set attribute test macros for all C/C++ (not for just C++11 etc.)
+ The builtin __has_attribute__ is defined in libcpp. */
+ cpp_define (pfile, "__has_attribute(STR)=__has_attribute__(STR)");
+ cpp_define (pfile, "__has_cpp_attribute(STR)=__has_attribute__(STR)");
+
if (c_dialect_cxx ())
{
if (flag_weak && SUPPORTS_ONE_ONLY)
@@ -806,7 +811,10 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__DEPRECATED");
if (flag_rtti)
- cpp_define (pfile, "__GXX_RTTI");
+ {
+ cpp_define (pfile, "__GXX_RTTI");
+ cpp_define (pfile, "__cpp_rtti=199711");
+ }
if (cxx_dialect >= cxx11)
cpp_define (pfile, "__GXX_EXPERIMENTAL_CXX0X__");
@@ -824,13 +832,18 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_user_defined_literals=200809");
cpp_define (pfile, "__cpp_lambdas=200907");
cpp_define (pfile, "__cpp_constexpr=200704");
+ cpp_define (pfile, "__cpp_range_based_for=200907");
cpp_define (pfile, "__cpp_static_assert=200410");
cpp_define (pfile, "__cpp_decltype=200707");
cpp_define (pfile, "__cpp_attributes=200809");
cpp_define (pfile, "__cpp_rvalue_reference=200610");
cpp_define (pfile, "__cpp_variadic_templates=200704");
+ cpp_define (pfile, "__cpp_initializer_lists=200806");
+ cpp_define (pfile, "__cpp_delegating_constructors=200604");
+ cpp_define (pfile, "__cpp_nsdmi=200809");
+ cpp_define (pfile, "__cpp_inheriting_constructors=200802");
+ cpp_define (pfile, "__cpp_ref_qualifiers=200710");
cpp_define (pfile, "__cpp_alias_templates=200704");
- cpp_define (pfile, "__cpp_attribute_deprecated=201309");
}
if (cxx_dialect > cxx11)
{
@@ -853,7 +866,11 @@ c_cpp_builtins (cpp_reader *pfile)
/* Note that we define this for C as well, so that we know if
__attribute__((cleanup)) will interface with EH. */
if (flag_exceptions)
- cpp_define (pfile, "__EXCEPTIONS");
+ {
+ cpp_define (pfile, "__EXCEPTIONS");
+ if (c_dialect_cxx ())
+ cpp_define (pfile, "__cpp_exceptions=199711");
+ }
/* Represents the C++ ABI version, always defined so it can be used while
preprocessing C and assembler. */
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index d2c231c..357d137 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -37,6 +37,8 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "wide-int.h"
+#include "attribs.h"
+
/* We may keep statistics about how long which files took to compile. */
static int header_time, body_time;
static splay_tree file_info_tree;
@@ -62,6 +64,7 @@ static void cb_ident (cpp_reader *, unsigned int, const cpp_string *);
static void cb_def_pragma (cpp_reader *, unsigned int);
static void cb_define (cpp_reader *, unsigned int, cpp_hashnode *);
static void cb_undef (cpp_reader *, unsigned int, cpp_hashnode *);
+static int cb_has_attribute (cpp_reader *);
void
init_c_lex (void)
@@ -86,6 +89,7 @@ init_c_lex (void)
cb->def_pragma = cb_def_pragma;
cb->valid_pch = c_common_valid_pch;
cb->read_pch = c_common_read_pch;
+ cb->has_attribute = cb_has_attribute;
/* Set the debug callbacks if we can use them. */
if ((debug_info_level == DINFO_LEVEL_VERBOSE
@@ -283,6 +287,75 @@ cb_undef (cpp_reader * ARG_UNUSED (pfile), source_location loc,
(*debug_hooks->undef) (SOURCE_LINE (map, loc),
(const char *) NODE_NAME (node));
}
+
+/* Callback for has_attribute. */
+static int
+cb_has_attribute (cpp_reader *pfile)
+{
+ int result = 0;
+ bool paren = false;
+ tree attr_ns = NULL_TREE, attr_id = NULL_TREE, attr_name = NULL_TREE;
+ const cpp_token *token;
+
+ token = cpp_get_token (pfile);
+ if (token->type == CPP_OPEN_PAREN)
+ {
+ paren = true;
+ token = cpp_get_token (pfile);
+ }
+
+ if (token->type == CPP_NAME)
+ {
+ //node = token->val.node.node;
+ const cpp_token *nxt_token = cpp_peek_token (pfile, 0);
+ if (c_dialect_cxx() && nxt_token->type == CPP_SCOPE)
+ {
+ nxt_token = cpp_get_token (pfile); // Eat scope.
+ nxt_token = cpp_get_token (pfile);
+ if (nxt_token->type == CPP_NAME)
+ {
+ attr_ns = get_identifier (
+ (const char *) cpp_token_as_text (pfile, token));
+ attr_id = get_identifier (
+ (const char *) cpp_token_as_text (pfile, nxt_token));
+ attr_name = build_tree_list (attr_ns, attr_id);
+ }
+ else
+ cpp_error (pfile, CPP_DL_ERROR,
+ "attribute identifier required after scope");
+ }
+ else
+ {
+ attr_ns = get_identifier ("gnu");
+ attr_id = get_identifier (
+ (const char *) cpp_token_as_text (pfile, token));
+ attr_name = build_tree_list (attr_ns, attr_id);
+ }
+ if (attr_name)
+ {
+ const struct attribute_spec *attr = lookup_attribute_spec (attr_name);
+ if (attr)
+ {
+ if (is_attribute_p ("noreturn", TREE_VALUE (attr_name)))
+ result = 200809;
+ else if (is_attribute_p ("deprecated", TREE_VALUE (attr_name)))
+ result = 201309;
+ else
+ result = 1;
+ }
+ }
+ }
+ else
+ cpp_error (pfile, CPP_DL_ERROR,
+ "operator \"__has_attribute__\" requires an identifier");
+
+ if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
+ cpp_error (pfile, CPP_DL_ERROR,
+ "missing ')' after \"__has_attribute__\"");
+
+ return result;
+}
+
/* Read a token and return its type. Fill *VALUE with its value, if
applicable. Fill *CPP_FLAGS with the token's flags, if it is
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a3ef629..4c96eb6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2014-11-10 Edward Smith-Rowland <3dw4rd@verizon.net>
+
+ * g++.dg/cpp1y/feat-cxx11.C: Test new feature macros for C++98
+ and C++11; Test existence of __has_cpp_attribute; Test C++11
+ attributes.
+ * g++.dg/cpp1y/feat-cxx11-neg.C: Ditto.
+ * g++.dg/cpp1y/feat-cxx14.C: Ditto and test for C++14 attributes.
+ * g++.dg/cpp1y/feat-cxx98.C: Test new feature macros for C++98.
+ * g++.dg/cpp1y/feat-cxx98-neg.C: Ditto.
+ * g++.dg/cpp1y/feat-neg.C: Test that __cpp_rtti, _cpp_exceptions
+ will be undefined for -fno-rtti -fno-exceptions.
+
2014-11-10 Richard Biener <rguenther@suse.de>
PR tree-optimization/63800
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C
index 8442d61..a5b41f4 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C
@@ -41,9 +41,13 @@
# error "__cpp_runtime_arrays" // { dg-error "error" }
#endif
-// Attribute checks:
+// C++14 attributes:
// Attribute [[deprecated]] is allowed in C++11 as an extension (with pedwarn).
-//#ifndef __cpp_attribute_deprecated
-//# error "__cpp_attribute_deprecated"
+//#ifdef __has_cpp_attribute
+//# if __has_cpp_attribute(deprecated) == 201309
+//# error "__has_cpp_attribute(deprecated)" // { }
+//# endif
+//#else
+//# error "__has_cpp_attribute"
//#endif
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C
index b47311f..3d02e23 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C
@@ -1,6 +1,20 @@
// { dg-do compile }
// { dg-options "-std=gnu++11" }
+// C++98 features:
+
+#ifndef __cpp_rtti
+# error "__cpp_rtti"
+#elif __cpp_rtti != 199711
+# error "__cpp_rtti != 199711"
+#endif
+
+#ifndef __cpp_exceptions
+# error "__cpp_exceptions"
+#elif __cpp_exceptions != 199711
+# error "__cpp_exceptions != 199711"
+#endif
+
// C++11 features:
#ifndef __cpp_unicode_characters
@@ -39,6 +53,12 @@
# error "__cpp_constexpr != 200704"
#endif
+#ifndef __cpp_range_based_for
+# error "__cpp_range_based_for"
+#elif __cpp_range_based_for != 200907
+# error "__cpp_range_based_for != 200907"
+#endif
+
#ifndef __cpp_static_assert
# error "__cpp_static_assert"
#elif __cpp_static_assert != 200410
@@ -69,6 +89,36 @@
# error "__cpp_variadic_templates != 200704"
#endif
+#ifndef __cpp_initializer_lists
+# error "__cpp_initializer_lists"
+#elif __cpp_initializer_lists != 200806
+# error "__cpp_initializer_lists != 200806"
+#endif
+
+#ifndef __cpp_delegating_constructors
+# error "__cpp_delegating_constructors"
+#elif __cpp_delegating_constructors != 200604
+# error "__cpp_delegating_constructors != 200604"
+#endif
+
+#ifndef __cpp_nsdmi
+# error "__cpp_nsdmi"
+#elif __cpp_nsdmi != 200809
+# error "__cpp_nsdmi != 200809"
+#endif
+
+#ifndef __cpp_inheriting_constructors
+# error "__cpp_inheriting_constructors"
+#elif __cpp_inheriting_constructors!= 200802
+# error "__cpp_inheriting_constructors != 200802"
+#endif
+
+#ifndef __cpp_ref_qualifiers
+# error "__cpp_ref_qualifiers"
+#elif __cpp_ref_qualifiers != 200710
+# error "__cpp_ref_qualifiers != 200710"
+#endif
+
#ifndef __cpp_alias_templates
# error "__cpp_alias_templates"
#elif __cpp_alias_templates != 200704
@@ -83,11 +133,38 @@
# error "__cpp_binary_literals != 201304"
#endif
-// Attribute checks:
+// C++11 attributes:
+
+#ifdef __has_cpp_attribute
+# if ! __has_cpp_attribute(noreturn)
+# error "__has_cpp_attribute(noreturn)"
+# elif __has_cpp_attribute(noreturn) != 200809
+# error "__has_cpp_attribute(noreturn) != 200809"
+# endif
+#else
+# error "__has_cpp_attribute"
+#endif
+
+#ifdef __has_cpp_attribute
+// Attribute carries_dependency not in yet.
+//# if ! __has_cpp_attribute(carries_dependency)
+//# error "__has_cpp_attribute(carries_dependency)"
+//# elif __has_cpp_attribute(carries_dependency) != 200809
+//# error "__has_cpp_attribute(carries_dependency) != 200809"
+//# endif
+#else
+# error "__has_cpp_attribute"
+#endif
+
+// C++14 attributes:
// Attribute [[deprecated]] is allowed in C++11 as an extension (with pedwarn).
-#ifndef __cpp_attribute_deprecated
-# error "__cpp_attribute_deprecated"
-#elif __cpp_attribute_deprecated != 201309
-# error "__cpp_attribute_deprecated != 201309"
+#ifdef __has_cpp_attribute
+# if ! __has_cpp_attribute(deprecated)
+# error "__has_cpp_attribute(deprecated)"
+# elif __has_cpp_attribute(deprecated) != 201309
+# error "__has_cpp_attribute(deprecated) != 201309"
+# endif
+#else
+# error "__has_cpp_attribute"
#endif
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C
index aa58fe1..74748cb 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C
@@ -1,6 +1,20 @@
// { dg-do compile { target c++14 } }
// { dg-options "-I${srcdir}/g++.dg/cpp1y -I${srcdir}/g++.dg/cpp1y/testinc" }
+// C++98 features:
+
+#ifndef __cpp_rtti
+# error "__cpp_rtti"
+#elif __cpp_rtti != 199711
+# error "__cpp_rtti != 199711"
+#endif
+
+#ifndef __cpp_exceptions
+# error "__cpp_exceptions"
+#elif __cpp_exceptions != 199711
+# error "__cpp_exceptions != 199711"
+#endif
+
// C++11 features:
#ifndef __cpp_unicode_characters
@@ -39,6 +53,12 @@
# error "__cpp_constexpr != 200704"
#endif
+#ifndef __cpp_range_based_for
+# error "__cpp_range_based_for"
+#elif __cpp_range_based_for != 200907
+# error "__cpp_range_based_for != 200907"
+#endif
+
#ifndef __cpp_static_assert
# error "__cpp_static_assert"
#elif __cpp_static_assert != 200410
@@ -69,6 +89,36 @@
# error "__cpp_variadic_templates != 200704"
#endif
+#ifndef __cpp_initializer_lists
+# error "__cpp_initializer_lists"
+#elif __cpp_initializer_lists != 200806
+# error "__cpp_initializer_lists != 200806"
+#endif
+
+#ifndef __cpp_delegating_constructors
+# error "__cpp_delegating_constructors"
+#elif __cpp_delegating_constructors != 200604
+# error "__cpp_delegating_constructors != 200604"
+#endif
+
+#ifndef __cpp_nsdmi
+# error "__cpp_nsdmi"
+#elif __cpp_nsdmi != 200809
+# error "__cpp_nsdmi != 200809"
+#endif
+
+#ifndef __cpp_inheriting_constructors
+# error "__cpp_inheriting_constructors"
+#elif __cpp_inheriting_constructors!= 200802
+# error "__cpp_inheriting_constructors != 200802"
+#endif
+
+#ifndef __cpp_ref_qualifiers
+# error "__cpp_ref_qualifiers"
+#elif __cpp_ref_qualifiers != 200710
+# error "__cpp_ref_qualifiers != 200710"
+#endif
+
#ifndef __cpp_alias_templates
# error "__cpp_alias_templates"
#elif __cpp_alias_templates != 200704
@@ -145,12 +195,39 @@
# error "__cpp_runtime_arrays != 201304"
#endif
-// Attribute checks:
+// C++11 attributes:
-#ifndef __cpp_attribute_deprecated
-# error "__cpp_attribute_deprecated"
-#elif __cpp_attribute_deprecated != 201309
-# error "__cpp_attribute_deprecated != 201309"
+#ifdef __has_cpp_attribute
+# if ! __has_cpp_attribute(noreturn)
+# error "__has_cpp_attribute(noreturn)"
+# elif __has_cpp_attribute(noreturn) != 200809
+# error "__has_cpp_attribute(noreturn) != 200809"
+# endif
+#else
+# error "__has_cpp_attribute"
+#endif
+
+// Attribute carries_dependency not in yet.
+//#ifdef __has_cpp_attribute
+//# if ! __has_cpp_attribute(carries_dependency)
+//# error "__has_cpp_attribute(carries_dependency)"
+//# elif __has_cpp_attribute(carries_dependency) != 200809
+//# error "__has_cpp_attribute(carries_dependency) != 200809"
+//# endif
+//#else
+//# error "__has_cpp_attribute"
+//#endif
+
+// C++14 attributes:
+
+#ifdef __has_cpp_attribute
+# if ! __has_cpp_attribute(deprecated)
+# error "__has_cpp_attribute(deprecated)"
+# elif __has_cpp_attribute(deprecated) != 201309
+# error "__has_cpp_attribute(deprecated) != 201309"
+# endif
+#else
+# error "__has_cpp_attribute"
#endif
// Include checks:
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C
index 3d75f98..e25cac3 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C
@@ -51,6 +51,26 @@
# error "__cpp_variadic_templates" // { dg-error "error" }
#endif
+#ifndef __cpp_initializer_lists
+# error "__cpp_initializer_lists" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_delegating_constructors
+# error "__cpp_delegating_constructors" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_nsdmi
+# error "__cpp_nsdmi" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_inheriting_constructors
+# error "__cpp_inheriting_constructors" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_ref_qualifiers
+# error "__cpp_ref_qualifiers" // { dg-error "error" }
+#endif
+
#ifndef __cpp_alias_templates
# error "__cpp_alias_templates" // { dg-error "error" }
#endif
@@ -95,8 +115,32 @@
//# error "__cpp_sized_deallocation"
//#endif
-// Attribute checks:
+// C++11 attributes:
-#ifndef __cpp_attribute_deprecated
-# error "__cpp_attribute_deprecated" // { dg-error "error" }
+#ifdef __has_cpp_attribute
+# if __has_cpp_attribute(noreturn) == 200809
+# error "__has_cpp_attribute(noreturn) == 200809" // { dg-error "error" }
+# endif
+#else
+# error "__has_cpp_attribute"
#endif
+
+// Attribute carries_dependency not in yet.
+//#ifdef __has_cpp_attribute
+//# if __has_cpp_attribute(carries_dependency) == 200809
+//# error "__has_cpp_attribute(carries_dependency) == 200809" // { }
+//# endif
+//#else
+//# error "__has_cpp_attribute"
+//#endif
+
+// C++14 attributes:
+
+// Attribute [[deprecated]] is allowed in C++11 as an extension (with pedwarn).
+//#ifdef __has_cpp_attribute
+//# if __has_cpp_attribute(deprecated) == 201309
+//# error "__has_cpp_attribute(deprecated)" // { }
+//# endif
+//#else
+//# error "__has_cpp_attribute"
+//#endif
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx98.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx98.C
index e6b3d77..dce7029 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx98.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx98.C
@@ -1,6 +1,20 @@
// { dg-do compile { target c++98_only } }
// { dg-options "" }
+// C++98 features:
+
+#ifndef __cpp_rtti
+# error "__cpp_rtti"
+#elif __cpp_rtti != 199711
+# error "__cpp_rtti != 199711"
+#endif
+
+#ifndef __cpp_exceptions
+# error "__cpp_exceptions"
+#elif __cpp_exceptions != 199711
+# error "__cpp_exceptions != 199711"
+#endif
+
// C++14 features allowed in C++98 in non-ANSI modes:
#ifndef __cpp_binary_literals
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-neg.C b/gcc/testsuite/g++.dg/cpp1y/feat-neg.C
new file mode 100644
index 0000000..9f4a041
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-neg.C
@@ -0,0 +1,12 @@
+// { dg-do compile }
+// { dg-options "-fno-rtti -fno-exceptions" }
+
+// C++98 features with explicit opt-out:
+
+#ifndef __cpp_rtti
+# error "__cpp_rtti" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_exceptions
+# error "__cpp_exceptions" // { dg-error "error" }
+#endif