From: Richard Smith Date: Mon, 17 Feb 2014 23:25:27 +0000 (+0000) Subject: PR18870: Parse language linkage specifiers properly if the string-literal is X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5d7b05137594183bfe330cd8739930faa4234b1b;p=clang PR18870: Parse language linkage specifiers properly if the string-literal is spelled in an interesting way. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201536 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e7f4fdbfbb..910263c4f2 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -222,7 +222,10 @@ def note_function_suggestion : Note<"did you mean %0?">; def err_ellipsis_first_arg : Error< "ISO C requires a named argument before '...'">; def err_declarator_need_ident : Error<"declarator requires an identifier">; -def err_bad_language : Error<"unknown linkage language">; +def err_language_linkage_spec_unknown : Error<"unknown linkage language">; +def err_language_linkage_spec_not_ascii : Error< + "string literal in language linkage specifier cannot have an " + "encoding-prefix">; def warn_use_out_of_scope_declaration : Warning< "use of out-of-scope declaration of %0">; def err_inline_non_function : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d32507a06d..894e43493f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4661,8 +4661,7 @@ public: // Decl *ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, - SourceLocation LangLoc, - StringRef Lang, + Expr *LangStr, SourceLocation LBraceLoc); Decl *ActOnFinishLinkageSpecification(Scope *S, Decl *LinkageSpec, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 5d68453e3f..b95eb87a6f 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -279,27 +279,16 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, /// 'extern' string-literal declaration /// Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { - assert(Tok.is(tok::string_literal) && "Not a string literal!"); - SmallString<8> LangBuffer; - bool Invalid = false; - StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); - if (Invalid) - return 0; - - // FIXME: This is incorrect: linkage-specifiers are parsed in translation - // phase 7, so string-literal concatenation is supposed to occur. - // extern "" "C" "" "+" "+" { } is legal. - if (Tok.hasUDSuffix()) - Diag(Tok, diag::err_invalid_string_udl); - SourceLocation Loc = ConsumeStringToken(); + assert(isTokenStringLiteral() && "Not a string literal!"); + ExprResult Lang = ParseStringLiteralExpression(false); ParseScope LinkageScope(this, Scope::DeclScope); - Decl *LinkageSpec - = Actions.ActOnStartLinkageSpecification(getCurScope(), - DS.getSourceRange().getBegin(), - Loc, Lang, - Tok.is(tok::l_brace) ? Tok.getLocation() - : SourceLocation()); + Decl *LinkageSpec = + Lang.isInvalid() + ? 0 + : Actions.ActOnStartLinkageSpecification( + getCurScope(), DS.getSourceRange().getBegin(), Lang.take(), + Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); @@ -313,8 +302,9 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { // ... but anyway remember that such an "extern" was seen. DS.setExternInLinkageSpec(true); ParseExternalDeclaration(attrs, &DS); - return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, - SourceLocation()); + return LinkageSpec ? Actions.ActOnFinishLinkageSpecification( + getCurScope(), LinkageSpec, SourceLocation()) + : 0; } DS.abort(); @@ -331,8 +321,9 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { } T.consumeClose(); - return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, - T.getCloseLocation()); + return LinkageSpec ? Actions.ActOnFinishLinkageSpecification( + getCurScope(), LinkageSpec, T.getCloseLocation()) + : 0; } /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index ffe9ae8336..5752959a5a 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -830,7 +830,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParseExplicitInstantiation(Declarator::FileContext, ExternLoc, TemplateLoc, DeclEnd)); } - // FIXME: Detect C++ linkage specifications here? goto dont_know; case tok::kw___if_exists: @@ -960,7 +959,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, // If the declspec consisted only of 'extern' and we have a string // literal following it, this must be a C++ linkage specifier like // 'extern "C"'. - if (Tok.is(tok::string_literal) && getLangOpts().CPlusPlus && + if (getLangOpts().CPlusPlus && isTokenStringLiteral() && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { Decl *TheDecl = ParseLinkage(DS, Declarator::FileContext); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a16c843780..5912bb82ea 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -11071,29 +11071,36 @@ FinishedParams: /// ActOnStartLinkageSpecification - Parsed the beginning of a C++ /// linkage specification, including the language and (if present) -/// the '{'. ExternLoc is the location of the 'extern', LangLoc is -/// the location of the language string literal, which is provided -/// by Lang/StrSize. LBraceLoc, if valid, provides the location of +/// the '{'. ExternLoc is the location of the 'extern', Lang is the +/// language string literal. LBraceLoc, if valid, provides the location of /// the '{' brace. Otherwise, this linkage specification does not /// have any braces. Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, - SourceLocation LangLoc, - StringRef Lang, + Expr *LangStr, SourceLocation LBraceLoc) { + StringLiteral *Lit = cast(LangStr); + if (!Lit->isAscii()) { + Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_not_ascii) + << LangStr->getSourceRange(); + return 0; + } + + StringRef Lang = Lit->getString(); LinkageSpecDecl::LanguageIDs Language; - if (Lang == "\"C\"") + if (Lang == "C") Language = LinkageSpecDecl::lang_c; - else if (Lang == "\"C++\"") + else if (Lang == "C++") Language = LinkageSpecDecl::lang_cxx; else { - Diag(LangLoc, diag::err_bad_language); + Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_unknown) + << LangStr->getSourceRange(); return 0; } // FIXME: Add all the various semantics of linkage specifications - LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, - ExternLoc, LangLoc, Language, + LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, ExternLoc, + LangStr->getExprLoc(), Language, LBraceLoc.isValid()); CurContext->addDecl(D); PushDeclContext(S, D); @@ -11107,13 +11114,11 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, Decl *LinkageSpec, SourceLocation RBraceLoc) { - if (LinkageSpec) { - if (RBraceLoc.isValid()) { - LinkageSpecDecl* LSDecl = cast(LinkageSpec); - LSDecl->setRBraceLoc(RBraceLoc); - } - PopDeclContext(); + if (RBraceLoc.isValid()) { + LinkageSpecDecl* LSDecl = cast(LinkageSpec); + LSDecl->setRBraceLoc(RBraceLoc); } + PopDeclContext(); return LinkageSpec; } diff --git a/test/Parser/cxx11-user-defined-literals.cpp b/test/Parser/cxx11-user-defined-literals.cpp index 31032e7f7f..a7446529ae 100644 --- a/test/Parser/cxx11-user-defined-literals.cpp +++ b/test/Parser/cxx11-user-defined-literals.cpp @@ -15,7 +15,7 @@ _Pragma("comment(lib, \"foo\"_bar)") // expected-error {{user-defined suffix can #elif __has_include("foo"_bar) // expected-error {{expected "FILENAME" or }} #endif -extern "C++"_x {} // expected-error {{user-defined suffix cannot be used here}} expected-error {{unknown linkage language}} +extern "C++"_x {} // expected-error {{user-defined suffix cannot be used here}} int f() { asm("mov %eax, %rdx"_foo); // expected-error {{user-defined suffix cannot be used here}}