From patchwork Sun Nov 21 12:16:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 72441 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 31AF2B7157 for ; Sun, 21 Nov 2010 23:17:11 +1100 (EST) Received: (qmail 27180 invoked by alias); 21 Nov 2010 12:17:06 -0000 Received: (qmail 27165 invoked by uid 22791); 21 Nov 2010 12:17:02 -0000 X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL, BAYES_00, TW_BJ, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from fencepost.gnu.org (HELO fencepost.gnu.org) (140.186.70.10) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 21 Nov 2010 12:16:56 +0000 Received: from eggs.gnu.org ([140.186.70.92]:37572) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1PK8qi-00061S-2T for gcc-patches@gnu.org; Sun, 21 Nov 2010 07:16:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PK8qi-0002ff-0V for gcc-patches@gnu.org; Sun, 21 Nov 2010 07:16:53 -0500 Received: from smtp201.iad.emailsrvr.com ([207.97.245.201]:55870) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PK8qh-0002fY-Pb for gcc-patches@gnu.org; Sun, 21 Nov 2010 07:16:51 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp40.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 28D223501FD for ; Sun, 21 Nov 2010 07:16:51 -0500 (EST) Received: from dynamic2.wm-web.iad.mlsrvr.com (dynamic2.wm-web.iad1a.rsapps.net [192.168.2.151]) by smtp40.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 0D5DA3501B1 for ; Sun, 21 Nov 2010 07:16:51 -0500 (EST) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic2.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id F40C228E8066 for ; Sun, 21 Nov 2010 07:16:50 -0500 (EST) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Sun, 21 Nov 2010 13:16:50 +0100 (CET) Date: Sun, 21 Nov 2010 13:16:50 +0100 (CET) Subject: Fix for PR objc/34033 "compiler accepts invalid string concatenation" From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1290341810.99812627@192.168.2.229> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch fixes PR objc/34033. Summarizing, GCC was accepting any number of "@" signs, in any position, when doing string concatenation. This patch adds the relevant checks to make sure there is a single '@' sign before each string. Testcases for both Objective-C and Objective-C++ are included. Ok to commit ? Thanks Index: c-family/ChangeLog =================================================================== --- c-family/ChangeLog (revision 166987) +++ c-family/ChangeLog (working copy) @@ -1,3 +1,9 @@ +2010-11-21 Nicola Pero + + 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 PR c++/16189 Index: c-family/c-lex.c =================================================================== --- c-family/c-lex.c (revision 166987) +++ c-family/c-lex.c (working copy) @@ -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) Index: testsuite/ChangeLog =================================================================== --- testsuite/ChangeLog (revision 166987) +++ testsuite/ChangeLog (working copy) @@ -1,3 +1,11 @@ +2010-11-21 Nicola Pero + + 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 * gcc.target/sparc/sparc-align-1.c: New test. Index: testsuite/objc.dg/strings-1.m =================================================================== --- testsuite/objc.dg/strings-1.m (revision 0) +++ testsuite/objc.dg/strings-1.m (revision 0) @@ -0,0 +1,28 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#ifndef __NEXT_RUNTIME__ +#include +#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" } */ Index: testsuite/objc.dg/strings-2.m =================================================================== --- testsuite/objc.dg/strings-2.m (revision 0) +++ testsuite/objc.dg/strings-2.m (revision 0) @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero , 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 /* 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; +} Index: testsuite/obj-c++.dg/strings-1.mm =================================================================== --- testsuite/obj-c++.dg/strings-1.mm (revision 0) +++ testsuite/obj-c++.dg/strings-1.mm (revision 0) @@ -0,0 +1,28 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include "../objc-obj-c++-shared/next-mapping.h" +#ifndef __NEXT_RUNTIME__ +#include +#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" } */ Index: testsuite/obj-c++.dg/strings-2.mm =================================================================== --- testsuite/obj-c++.dg/strings-2.mm (revision 0) +++ testsuite/obj-c++.dg/strings-2.mm (revision 0) @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero , 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 /* 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; +}