===================================================================
@@ -1,3 +1,9 @@
+2010-11-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ PR objc/34033
+ * c-lex.c (lex_string): Check that each Objective-C string in a
+ string concatenation sequence starts with exactly a single '@'.
+
2010-11-20 Nathan Froyd <froydnj@codesourcery.com>
PR c++/16189
===================================================================
@@ -891,7 +891,8 @@ interpret_fixed (const cpp_token *token,
UTF8STRING tokens into a tree, performing string constant
concatenation. TOK is the first of these. VALP is the location
to write the string into. OBJC_STRING indicates whether an '@' token
- preceded the incoming token.
+ preceded the incoming token (in that case, all the strings must
+ be preceded by a '@', but not other '@' should be present).
Returns the CPP token type of the result (CPP_STRING, CPP_WSTRING,
CPP_STRING32, CPP_STRING16, CPP_UTF8STRING, or CPP_OBJC_STRING).
@@ -918,6 +919,12 @@ lex_string (const cpp_token *tok, tree *
cpp_string str = tok->val.str;
cpp_string *strs = &str;
+ /* objc_at_sign_was_seen is only used when doing Objective-C string
+ concatenation. It is 'true' if we have seen an '@' before the
+ current string, and 'false' if not. We must see exactly one '@'
+ before each string. */
+ bool objc_at_sign_was_seen = false;
+
retry:
tok = cpp_get_token (parse_in);
switch (tok->type)
@@ -925,9 +932,12 @@ lex_string (const cpp_token *tok, tree *
case CPP_PADDING:
goto retry;
case CPP_ATSIGN:
- if (c_dialect_objc ())
+ if (objc_string)
{
- objc_string = true;
+ if (objc_at_sign_was_seen)
+ error ("repeated %<@%> before Objective-C string");
+
+ objc_at_sign_was_seen = true;
goto retry;
}
/* FALLTHROUGH */
@@ -948,6 +958,12 @@ lex_string (const cpp_token *tok, tree *
}
case CPP_STRING:
+ if (objc_string)
+ {
+ if (!objc_at_sign_was_seen)
+ error ("missing %<@%> before Objective-C string");
+ objc_at_sign_was_seen = false;
+ }
if (!concats)
{
gcc_obstack_init (&str_ob);
@@ -959,6 +975,10 @@ lex_string (const cpp_token *tok, tree *
goto retry;
}
+ /* It is an error if we saw a '@' with no following string. */
+ if (objc_at_sign_was_seen)
+ error ("stray %<@%> in program");
+
/* We have read one more token than we want. */
_cpp_backup_tokens (parse_in, 1);
if (concats)
===================================================================
@@ -1,3 +1,11 @@
+2010-11-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ PR objc/34033
+ * objc.dg/strings-1.m: New.
+ * objc.dg/strings-2.m: New.
+ * obj-c++.dg/strings-1.mm: New.
+ * obj-c++.dg/strings-2.mm: New.
+
2010-11-20 Eric Botcazou <ebotcazou@adacore.com>
* gcc.target/sparc/sparc-align-1.c: New test.
===================================================================
@@ -0,0 +1,28 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
+/* { dg-do compile } */
+
+#include "../objc-obj-c++-shared/Object1.h"
+#include "../objc-obj-c++-shared/next-mapping.h"
+#ifndef __NEXT_RUNTIME__
+#include <objc/NXConstStr.h>
+#endif
+
+/* The following are correct. */
+id test_valid1 = @"test";
+id test_valid2 = @"te" @"st";
+id test_valid3 = @"te" @"s" @"t";
+id test_valid4 = @ "t" @ "e" @ "s" @ "t";
+
+/* The following are not correct. */
+id test_invalid1 = @@"test"; /* { dg-error "stray .@. in program" } */
+const char *test_invalid2 = "test"@; /* { dg-error "stray .@. in program" } */
+const char *test_invalid3 = "test"@@; /* { dg-error "stray .@. in program" } */
+id test_invalid4 = @"te" "st"; /* { dg-error "missing .@. before Objective.C string" } */
+const char *test_invalid5 = "te" @"st"; /* { dg-error "expected" } */
+id test_invalid6 = @"te" @@"st"; /* { dg-error "repeated .@. before Objective-C string" } */
+id test_invalid7 = @@"te" @"st"; /* { dg-error "stray .@. in program" } */
+id test_invalid8 = @"te" @"s" "t"; /* { dg-error "missing .@. before Objective.C string" } */
+id test_invalid9 = @"te" "s" @"t"; /* { dg-error "missing .@. before Objective.C string" } */
+id test_invalidA = @"te" @"s" @@"t"; /* { dg-error "repeated .@. before Objective-C string" } */
+id test_invalidB = @"te" @@"s" @"t"; /* { dg-error "repeated .@. before Objective-C string" } */
+id test_invalidC = @"te" @"s" @"t" @; /* { dg-error "stray .@. in program" } */
===================================================================
@@ -0,0 +1,47 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
+
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+/* { dg-options "-fconstant-string-class=MyTestString" } */
+/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=MyTestString" { target *-*-darwin* } } */
+
+/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */
+
+#include "../objc-obj-c++-shared/Object1.h"
+#include "../objc-obj-c++-shared/next-mapping.h"
+
+#include <stdlib.h> /* For abort() */
+
+@interface MyTestString : Object
+{
+ char *string;
+ unsigned int len;
+}
+/* All strings should contain the C string 'test'. Call -check to
+ test that this is true. */
+- (void) check;
+@end
+
+@implementation MyTestString
+- (void) check
+{
+ if (len != 4 || string[0] != 't' || string[1] != 'e'
+ || string[2] != 's' || string[3] != 't' || string[4] != '\0')
+ abort ();
+}
+@end
+
+int main (void)
+{
+ MyTestString *test_valid1 = @"test";
+ MyTestString *test_valid2 = @"te" @"st";
+ MyTestString *test_valid3 = @"te" @"s" @"t";
+ MyTestString *test_valid4 = @ "t" @ "e" @ "s" @ "t";
+
+ [test_valid1 check];
+ [test_valid2 check];
+ [test_valid3 check];
+ [test_valid4 check];
+
+ return 0;
+}
===================================================================
@@ -0,0 +1,28 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
+/* { dg-do compile } */
+
+#include "../objc-obj-c++-shared/Object1.h"
+#include "../objc-obj-c++-shared/next-mapping.h"
+#ifndef __NEXT_RUNTIME__
+#include <objc/NXConstStr.h>
+#endif
+
+/* The following are correct. */
+id test_valid1 = @"test";
+id test_valid2 = @"te" @"st";
+id test_valid3 = @"te" @"s" @"t";
+id test_valid4 = @ "t" @ "e" @ "s" @ "t";
+
+/* The following are not correct. */
+id test_invalid1 = @@"test"; /* { dg-error "stray .@. in program" } */
+const char *test_invalid2 = "test"@; /* { dg-error "stray .@. in program" } */
+const char *test_invalid3 = "test"@@; /* { dg-error "stray .@. in program" } */
+id test_invalid4 = @"te" "st"; /* { dg-error "missing .@. before Objective.C string" } */
+const char *test_invalid5 = "te" @"st"; /* { dg-error "expected" } */
+id test_invalid6 = @"te" @@"st"; /* { dg-error "repeated .@. before Objective-C string" } */
+id test_invalid7 = @@"te" @"st"; /* { dg-error "stray .@. in program" } */
+id test_invalid8 = @"te" @"s" "t"; /* { dg-error "missing .@. before Objective.C string" } */
+id test_invalid9 = @"te" "s" @"t"; /* { dg-error "missing .@. before Objective.C string" } */
+id test_invalidA = @"te" @"s" @@"t"; /* { dg-error "repeated .@. before Objective-C string" } */
+id test_invalidB = @"te" @@"s" @"t"; /* { dg-error "repeated .@. before Objective-C string" } */
+id test_invalidC = @"te" @"s" @"t" @; /* { dg-error "stray .@. in program" } */
===================================================================
@@ -0,0 +1,47 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
+
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+/* { dg-options "-fconstant-string-class=MyTestString" } */
+/* { dg-options "-mno-constant-cfstrings -fconstant-string-class=MyTestString" { target *-*-darwin* } } */
+
+/* { dg-additional-sources "../objc-obj-c++-shared/Object1.mm" } */
+
+#include "../objc-obj-c++-shared/Object1.h"
+#include "../objc-obj-c++-shared/next-mapping.h"
+
+#include <stdlib.h> /* For abort() */
+
+@interface MyTestString : Object
+{
+ char *string;
+ unsigned int len;
+}
+/* All strings should contain the C string 'test'. Call -check to
+ test that this is true. */
+- (void) check;
+@end
+
+@implementation MyTestString
+- (void) check
+{
+ if (len != 4 || string[0] != 't' || string[1] != 'e'
+ || string[2] != 's' || string[3] != 't' || string[4] != '\0')
+ abort ();
+}
+@end
+
+int main (void)
+{
+ MyTestString *test_valid1 = @"test";
+ MyTestString *test_valid2 = @"te" @"st";
+ MyTestString *test_valid3 = @"te" @"s" @"t";
+ MyTestString *test_valid4 = @ "t" @ "e" @ "s" @ "t";
+
+ [test_valid1 check];
+ [test_valid2 check];
+ [test_valid3 check];
+ [test_valid4 check];
+
+ return 0;
+}