diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-18 07:07:28 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-18 07:07:28 +0000 |
commit | 965acbb321e94e36aa5365126eee46b97745fdbb (patch) | |
tree | b90c16f0aedbfca9146e07251c896cd22d9fd9c6 | |
parent | c6c16af963eddc3e9b75b5d2614d069e1162fe27 (diff) |
Allow "overloadable" functions in C to be declared as variadic without
any named parameters, e.g., this is accepted in C:
void f(...) __attribute__((overloadable));
although this would be rejected:
void f(...);
To do this, moved the checking of the "ellipsis without any named
arguments" condition from the parser into Sema (where it belongs anyway).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64902 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | docs/LanguageExtensions.html | 18 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.def | 2 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 3 | ||||
-rw-r--r-- | include/clang/Parse/DeclSpec.h | 13 | ||||
-rw-r--r-- | lib/Parse/DeclSpec.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 15 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 16 | ||||
-rw-r--r-- | test/Sema/overloadable.c | 3 |
10 files changed, 61 insertions, 17 deletions
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index dfffd2f5d6..67e60dec4d 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -112,6 +112,24 @@ int g(int) { } <i>// error: redeclaration of "g" must also have the "overloadabl </pre> </blockquote> +<p>Functions marked <tt>overloadable</tt> must have +prototypes. Therefore, the following code is ill-formed:</p> + +<blockquote> +<pre> +int h() __attribute__((overloadable)); <i>// error: h does not have a prototype</i> +</pre> +</blockquote> + +<p>However, <tt>overloadable</tt> functions are allowed to use a +ellipsis even if there are no named parameters (as is permitted in C++). This feature is particularly useful when combined with the <tt>unavailable</tt> attribute:</p> + +<blockquote> +<pre> +void honeypot(..) __attribute__((overloadable, unavailable)); <i>// calling me is an error</i> +</pre> +</blockquote> + <p>Functions declared with the <tt>overloadable</tt> attribute have their names mangled according to the same rules as C++ function names. For example, the three <tt>tgsin</tt> functions in our diff --git a/include/clang/Basic/DiagnosticParseKinds.def b/include/clang/Basic/DiagnosticParseKinds.def index 5134a28185..6d87c70a17 100644 --- a/include/clang/Basic/DiagnosticParseKinds.def +++ b/include/clang/Basic/DiagnosticParseKinds.def @@ -162,8 +162,6 @@ DIAG(err_illegal_decl_reference_to_reference, ERROR, "%0 declared as a reference to a reference") DIAG(err_argument_required_after_attribute, ERROR, "argument required after attribute") -DIAG(err_ellipsis_first_arg, ERROR, - "ISO C requires a named argument before '...'") DIAG(err_missing_param, ERROR, "expected parameter declarator") DIAG(err_unexpected_typedef_ident, ERROR, diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 16692412dc..fc4bfc9ad2 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -78,7 +78,8 @@ DIAG(warn_decl_in_param_list, WARNING, "declaration of %0 will not be visible outside of this function") DIAG(warn_implicit_function_decl, WARNING, "implicit declaration of function %0") - +DIAG(err_ellipsis_first_arg, ERROR, + "ISO C requires a named argument before '...'") DIAG(err_declarator_need_ident, ERROR, "declarator requires an identifier") DIAG(err_bad_language, ERROR, diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 4879f00be7..118d6a246e 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -503,10 +503,14 @@ struct DeclaratorChunk { /// and is treated as a K&R-style function. bool hasPrototype : 1; - /// isVariadic - If this function has a prototype, and if that proto ends - /// with ',...)', this is true. + /// isVariadic - If this function has a prototype, and if that + /// proto ends with ',...)', this is true. When true, EllipsisLoc + /// contains the location of the ellipsis. bool isVariadic : 1; + /// When isVariadic is true, the location of the ellipsis in the source. + unsigned EllipsisLoc; + /// The type qualifiers: const/volatile/restrict. /// The qualifier bitmask values are the same as in QualType. unsigned TypeQuals : 3; @@ -537,6 +541,10 @@ struct DeclaratorChunk { if (DeleteArgInfo) delete[] ArgInfo; } + + SourceLocation getEllipsisLoc() const { + return SourceLocation::getFromRawEncoding(EllipsisLoc); + } }; struct BlockPointerTypeInfo { @@ -646,6 +654,7 @@ struct DeclaratorChunk { /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. static DeclaratorChunk getFunction(bool hasProto, bool isVariadic, + SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, unsigned TypeQuals, SourceLocation Loc, Declarator &TheDeclarator); diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 4f1ef2490a..28c8149639 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -27,6 +27,7 @@ static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, + SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, unsigned TypeQuals, @@ -37,6 +38,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, I.Loc = Loc; I.Fun.hasPrototype = hasProto; I.Fun.isVariadic = isVariadic; + I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); I.Fun.DeleteArgInfo = false; I.Fun.TypeQuals = TypeQuals; I.Fun.NumArgs = NumArgs; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 953b552562..9974aea005 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2036,6 +2036,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // int() -> no prototype, no '...'. D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus, /*variadic*/ false, + SourceLocation(), /*arglist*/ 0, 0, DS.getTypeQualifiers(), LParenLoc, D), @@ -2069,19 +2070,11 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); bool IsVariadic = false; + SourceLocation EllipsisLoc; while (1) { if (Tok.is(tok::ellipsis)) { IsVariadic = true; - - // Check to see if this is "void(...)" which is not allowed. - if (!getLang().CPlusPlus && ParamInfo.empty()) { - // Otherwise, parse parameter type list. If it starts with an - // ellipsis, diagnose the malformed function. - Diag(Tok, diag::err_ellipsis_first_arg); - IsVariadic = false; // Treat this like 'void()'. - } - - ConsumeToken(); // Consume the ellipsis. + EllipsisLoc = ConsumeToken(); // Consume the ellipsis. break; } @@ -2201,6 +2194,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Remember that we parsed a function type, and remember the attributes. D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic, + EllipsisLoc, &ParamInfo[0], ParamInfo.size(), DS.getTypeQualifiers(), LParenLoc, D), @@ -2273,6 +2267,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // function type is always a K&R style function type, which is not varargs and // has no prototype. D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false, + SourceLocation(), &ParamInfo[0], ParamInfo.size(), /*TypeQuals*/0, LParenLoc, D), RLoc); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index f7eeef7556..d2e59ece35 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1296,7 +1296,8 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { ParseBlockId(); } else { // Otherwise, pretend we saw (void). - ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, + ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, + SourceLocation(), 0, 0, 0, CaretLoc, ParamInfo), CaretLoc); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0543b0adc6..92f167dcf2 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2928,7 +2928,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, Error = Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); Declarator D(DS, Declarator::BlockContext); - D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, 0, Loc, D), + D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), + 0, 0, 0, Loc, D), SourceLocation()); D.SetIdentifier(&II, Loc); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index e6aafdab08..a385a13f4c 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -474,6 +474,22 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the // function takes no arguments. T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals); + } else if (FTI.isVariadic) { + // We allow a zero-parameter variadic function in C if the + // function is marked with the "overloadable" + // attribute. Scan for this attribute now. + bool Overloadable = false; + for (const AttributeList *Attrs = D.getAttributes(); + Attrs; Attrs = Attrs->getNext()) { + if (Attrs->getKind() == AttributeList::AT_overloadable) { + Overloadable = true; + break; + } + } + + if (!Overloadable) + Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); + T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0); } else { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionTypeNoProto(T); diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c index 136f8e93d7..22ced49b61 100644 --- a/test/Sema/overloadable.c +++ b/test/Sema/overloadable.c @@ -42,9 +42,12 @@ double promote(double) __attribute__((__overloadable__)); long double promote(long double) __attribute__((__overloadable__)); void promote() __attribute__((__overloadable__)); // expected-error{{'overloadable' function 'promote' must have a prototype}} +void promote(...) __attribute__((__overloadable__, __unavailable__)); // \ + // expected-note{{unavailable function is declared here}} void test_promote(short* sp) { promote(1.0); + promote(sp); // expected-error{{call to function 'promote' that has been intentionally made unavailable}} } |