[cfe-commits] r124584 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h include/clang/Sema/DeclSpec.h lib/Parse/ParseDecl.cpp lib/Parse/ParseTemplate.cpp lib/Sema/SemaType.cpp test/SemaCXX/issue547.cpp
Douglas Gregor
dgregor at apple.com
Mon Jan 31 08:09:46 PST 2011
Author: dgregor
Date: Mon Jan 31 10:09:46 2011
New Revision: 124584
URL: http://llvm.org/viewvc/llvm-project?rev=124584&view=rev
Log:
Implement the suggested resolution to core issue 547, extended to also
allow ref-qualifiers on function types used as template type
arguments. GNU actually allows cv-qualifiers on function types in many
places where it shouldn't, so we currently categorize this as a GNU
extension.
Added:
cfe/trunk/test/SemaCXX/issue547.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/DeclSpec.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseTemplate.cpp
cfe/trunk/lib/Sema/SemaType.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan 31 10:09:46 2011
@@ -2475,6 +2475,10 @@
def err_invalid_ref_qualifier_function_type : Error<
"ref-qualifier '%select{&&|&}0' is only allowed on non-static member functions,"
" member function pointers, and typedefs of function types">;
+def ext_qualified_function_type_template_arg : ExtWarn<
+ "template argument of '%0' qualified function type is a GNU extension">,
+ InGroup<GNU>;
+
def err_invalid_qualified_function_pointer : Error<
"type qualifier is not allowed on this function %select{pointer|reference}0">;
def err_invalid_qualified_typedef_function_type_use : Error<
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jan 31 10:09:46 2011
@@ -1464,7 +1464,9 @@
TPResult TryParseFunctionDeclarator();
TPResult TryParseBracketDeclarator();
- TypeResult ParseTypeName(SourceRange *Range = 0);
+ TypeResult ParseTypeName(SourceRange *Range = 0,
+ Declarator::TheContext Context
+ = Declarator::TypeNameContext);
void ParseBlockId();
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Jan 31 10:09:46 2011
@@ -1177,7 +1177,8 @@
ConditionContext, // Condition declaration in a C++ if/switch/while/for.
TemplateParamContext,// Within a template parameter list.
CXXCatchContext, // C++ catch exception-declaration
- BlockLiteralContext // Block literal declarator.
+ BlockLiteralContext, // Block literal declarator.
+ TemplateTypeArgContext // Template type argument.
};
private:
@@ -1302,14 +1303,15 @@
bool mayOmitIdentifier() const {
return Context == TypeNameContext || Context == PrototypeContext ||
Context == TemplateParamContext || Context == CXXCatchContext ||
- Context == BlockLiteralContext;
+ Context == BlockLiteralContext || Context == TemplateTypeArgContext;
}
/// mayHaveIdentifier - Return true if the identifier is either optional or
/// required. This is true for normal declarators and prototypes, but not
/// typenames.
bool mayHaveIdentifier() const {
- return Context != TypeNameContext && Context != BlockLiteralContext;
+ return Context != TypeNameContext && Context != BlockLiteralContext &&
+ Context != TemplateTypeArgContext;
}
/// mayBeFollowedByCXXDirectInit - Return true if the declarator can be
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jan 31 10:09:46 2011
@@ -29,13 +29,14 @@
/// specifier-qualifier-list abstract-declarator[opt]
///
/// Called type-id in C++.
-TypeResult Parser::ParseTypeName(SourceRange *Range) {
+TypeResult Parser::ParseTypeName(SourceRange *Range,
+ Declarator::TheContext Context) {
// Parse the common declaration-specifiers piece.
DeclSpec DS;
ParseSpecifierQualifierList(DS);
// Parse the abstract-declarator, if present.
- Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ Declarator DeclaratorInfo(DS, Context);
ParseDeclarator(DeclaratorInfo);
if (Range)
*Range = DeclaratorInfo.getSourceRange();
Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Jan 31 10:09:46 2011
@@ -992,7 +992,8 @@
// Therefore, we initially try to parse a type-id.
if (isCXXTypeId(TypeIdAsTemplateArgument)) {
SourceLocation Loc = Tok.getLocation();
- TypeResult TypeArg = ParseTypeName();
+ TypeResult TypeArg = ParseTypeName(/*Range=*/0,
+ Declarator::TemplateTypeArgContext);
if (TypeArg.isInvalid())
return ParsedTemplateArgument();
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jan 31 10:09:46 2011
@@ -1512,6 +1512,7 @@
case Declarator::ForContext:
case Declarator::ConditionContext:
case Declarator::TypeNameContext:
+ case Declarator::TemplateTypeArgContext:
break;
}
@@ -1872,6 +1873,9 @@
// for a nonstatic member function, the function type to which a pointer
// to member refers, or the top-level function type of a function typedef
// declaration.
+ //
+ // Core issue 547 also allows cv-qualifiers on function types that are
+ // top-level template type arguments.
bool FreeFunction;
if (!D.getCXXScopeSpec().isSet()) {
FreeFunction = (D.getContext() != Declarator::MemberContext ||
@@ -1887,48 +1891,81 @@
// member refers, or the top-level function type of a function typedef
// declaration.
if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) &&
+ !(D.getContext() == Declarator::TemplateTypeArgContext &&
+ !D.isFunctionDeclarator()) &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
(FreeFunction ||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
- if (FnTy->getTypeQuals() != 0) {
- if (D.isFunctionDeclarator())
- Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
- else
- Diag(D.getIdentifierLoc(),
- diag::err_invalid_qualified_typedef_function_type_use)
- << FreeFunction;
- }
+ if (D.getContext() == Declarator::TemplateTypeArgContext) {
+ // Accept qualified function types as template type arguments as a GNU
+ // extension. This is also the subject of C++ core issue 547.
+ std::string Quals;
+ if (FnTy->getTypeQuals() != 0)
+ Quals = Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString();
+
+ switch (FnTy->getRefQualifier()) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ if (!Quals.empty())
+ Quals += ' ';
+ Quals += '&';
+ break;
- if (FnTy->getRefQualifier()) {
- if (D.isFunctionDeclarator()) {
- SourceLocation Loc = D.getIdentifierLoc();
- for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
- const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1);
- if (Chunk.Kind == DeclaratorChunk::Function &&
- Chunk.Fun.hasRefQualifier()) {
- Loc = Chunk.Fun.getRefQualifierLoc();
- break;
+ case RQ_RValue:
+ if (!Quals.empty())
+ Quals += ' ';
+ Quals += "&&";
+ break;
+ }
+
+ Diag(D.getIdentifierLoc(),
+ diag::ext_qualified_function_type_template_arg)
+ << Quals;
+ } else {
+ if (FnTy->getTypeQuals() != 0) {
+ if (D.isFunctionDeclarator())
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_qualified_function_type);
+ else
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_qualified_typedef_function_type_use)
+ << FreeFunction;
+ }
+
+ if (FnTy->getRefQualifier()) {
+ if (D.isFunctionDeclarator()) {
+ SourceLocation Loc = D.getIdentifierLoc();
+ for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
+ const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1);
+ if (Chunk.Kind == DeclaratorChunk::Function &&
+ Chunk.Fun.hasRefQualifier()) {
+ Loc = Chunk.Fun.getRefQualifierLoc();
+ break;
+ }
}
- }
- Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
- << (FnTy->getRefQualifier() == RQ_LValue)
- << FixItHint::CreateRemoval(Loc);
- } else {
- Diag(D.getIdentifierLoc(),
- diag::err_invalid_ref_qualifier_typedef_function_type_use)
- << FreeFunction
- << (FnTy->getRefQualifier() == RQ_LValue);
+ Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
+ << (FnTy->getRefQualifier() == RQ_LValue)
+ << FixItHint::CreateRemoval(Loc);
+ } else {
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_ref_qualifier_typedef_function_type_use)
+ << FreeFunction
+ << (FnTy->getRefQualifier() == RQ_LValue);
+ }
}
- }
- // Strip the cv-quals and ref-qualifier from the type.
- FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
- EPI.TypeQuals = 0;
- EPI.RefQualifier = RQ_None;
+ // Strip the cv-qualifiers and ref-qualifiers from the type.
+ FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
+ EPI.TypeQuals = 0;
+ EPI.RefQualifier = RQ_None;
- T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
- FnTy->getNumArgs(), EPI);
+ T = Context.getFunctionType(FnTy->getResultType(),
+ FnTy->arg_type_begin(),
+ FnTy->getNumArgs(), EPI);
+ }
}
}
@@ -1997,6 +2034,7 @@
case Declarator::ConditionContext:
case Declarator::CXXCatchContext:
case Declarator::BlockLiteralContext:
+ case Declarator::TemplateTypeArgContext:
// FIXME: We may want to allow parameter packs in block-literal contexts
// in the future.
Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter);
Added: cfe/trunk/test/SemaCXX/issue547.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/issue547.cpp?rev=124584&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/issue547.cpp (added)
+++ cfe/trunk/test/SemaCXX/issue547.cpp Mon Jan 31 10:09:46 2011
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T>
+struct classify_function {
+ static const unsigned value = 0;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args...)> {
+ static const unsigned value = 1;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args...) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
+ static const unsigned value = 2;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args...) volatile> { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}}
+ static const unsigned value = 3;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args...) const volatile> { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}}
+ static const unsigned value = 4;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args......)> {
+ static const unsigned value = 5;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args......) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
+ static const unsigned value = 6;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args......) volatile> { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}}
+ static const unsigned value = 7;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args......) const volatile> { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}}
+ static const unsigned value = 8;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args......) &&> { // expected-warning{{template argument of '&&' qualified function type is a GNU extension}}
+ static const unsigned value = 9;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args......) const &> { // expected-warning{{template argument of 'const &' qualified function type is a GNU extension}}
+ static const unsigned value = 10;
+};
+
+typedef void f0(int) const;
+typedef void f1(int, float...) const volatile;
+typedef void f2(int, double, ...) &&;
+typedef void f3(int, double, ...) const &;
+
+int check0[classify_function<f0>::value == 2? 1 : -1];
+int check1[classify_function<f1>::value == 8? 1 : -1];
+int check2[classify_function<f2>::value == 9? 1 : -1];
+int check3[classify_function<f3>::value == 10? 1 : -1];
More information about the cfe-commits
mailing list