When deciding how to parse "= something" as part of a member

declaration, determine whether the declaration will end up declaring a
function using semantic criteria (e.g., it will have function type)
rather than purely syntactic criteria (e.g., it has the form of a
function declarator). Fixes <rdar://problem/9670557>.

llvm-svn: 133854
This commit is contained in:
Douglas Gregor 2011-06-25 00:56:27 +00:00
parent 03bf47c0f0
commit c15b0cfc1f
6 changed files with 144 additions and 49 deletions

View File

@ -1697,6 +1697,14 @@ public:
return const_cast<Declarator*>(this)->getFunctionTypeInfo();
}
/// \brief Determine whether the declaration that will be produced from
/// this declaration will be a function.
///
/// A declaration can declare a function even if the declarator itself
/// isn't a function declarator, if the type specifier refers to a function
/// type. This routine checks for both cases.
bool isDeclarationOfFunction() const;
/// takeAttributes - Takes attributes from the given parsed-attributes
/// set and add them to this declarator.
///

View File

@ -0,0 +1,62 @@
//===--- LocInfoType.h - Parsed Type with Location Information---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the LocInfoType class, which holds a type and its
// source-location information.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_SEMA_LOCINFOTYPE_H
#define LLVM_CLANG_SEMA_LOCINFOTYPE_H
#include "clang/AST/Type.h"
namespace clang {
class TypeSourceInfo;
/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator
/// parsing.
///
/// LocInfoType is a "transient" type, only needed for passing to/from Parser
/// and Sema, when we want to preserve type source info for a parsed type.
/// It will not participate in the type system semantics in any way.
class LocInfoType : public Type {
enum {
// The last number that can fit in Type's TC.
// Avoids conflict with an existing Type class.
LocInfo = Type::TypeLast + 1
};
TypeSourceInfo *DeclInfo;
LocInfoType(QualType ty, TypeSourceInfo *TInfo)
: Type((TypeClass)LocInfo, ty, ty->isDependentType(),
ty->isVariablyModifiedType(),
ty->containsUnexpandedParameterPack()),
DeclInfo(TInfo) {
assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
}
friend class Sema;
public:
QualType getType() const { return getCanonicalTypeInternal(); }
TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; }
void getAsStringInternal(std::string &Str,
const PrintingPolicy &Policy) const;
static bool classof(const Type *T) {
return T->getTypeClass() == (TypeClass)LocInfo;
}
static bool classof(const LocInfoType *) { return true; }
};
} // end namespace clang
#endif // LLVM_CLANG_SEMA_LOCINFOTYPE_H

View File

@ -20,6 +20,7 @@
#include "clang/Sema/IdentifierResolver.h"
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/LocInfoType.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
@ -157,43 +158,6 @@ namespace sema {
class TemplateDeductionInfo;
}
/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator
/// parsing.
///
/// LocInfoType is a "transient" type, only needed for passing to/from Parser
/// and Sema, when we want to preserve type source info for a parsed type.
/// It will not participate in the type system semantics in any way.
class LocInfoType : public Type {
enum {
// The last number that can fit in Type's TC.
// Avoids conflict with an existing Type class.
LocInfo = Type::TypeLast + 1
};
TypeSourceInfo *DeclInfo;
LocInfoType(QualType ty, TypeSourceInfo *TInfo)
: Type((TypeClass)LocInfo, ty, ty->isDependentType(),
ty->isVariablyModifiedType(),
ty->containsUnexpandedParameterPack()),
DeclInfo(TInfo) {
assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
}
friend class Sema;
public:
QualType getType() const { return getCanonicalTypeInternal(); }
TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; }
void getAsStringInternal(std::string &Str,
const PrintingPolicy &Policy) const;
static bool classof(const Type *T) {
return T->getTypeClass() == (TypeClass)LocInfo;
}
static bool classof(const LocInfoType *) { return true; }
};
// FIXME: No way to easily map from TemplateTypeParmTypes to
// TemplateTypeParmDecls, so we have this horrible PointerUnion.
typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,

View File

@ -1822,7 +1822,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
Diag(Tok, diag::err_bitfield_member_init);
SkipUntil(tok::comma, true, true);
} else {
HasDeferredInitializer = !DeclaratorInfo.isFunctionDeclarator() &&
HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_static &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
@ -1831,7 +1831,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (!HasDeferredInitializer) {
SourceLocation EqualLoc;
Init = ParseCXXMemberInitializer(
DeclaratorInfo.isFunctionDeclarator(), EqualLoc);
DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
if (Init.isInvalid())
SkipUntil(tok::comma, true, true);
}

View File

@ -13,8 +13,10 @@
#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/LocInfoType.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Lex/Preprocessor.h"
@ -213,6 +215,59 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
return I;
}
bool Declarator::isDeclarationOfFunction() const {
if (isFunctionDeclarator())
return true;
switch (DS.getTypeSpecType()) {
case TST_auto:
case TST_bool:
case TST_char:
case TST_char16:
case TST_char32:
case TST_class:
case TST_decimal128:
case TST_decimal32:
case TST_decimal64:
case TST_double:
case TST_enum:
case TST_error:
case TST_float:
case TST_int:
case TST_struct:
case TST_union:
case TST_unknown_anytype:
case TST_unspecified:
case TST_void:
case TST_wchar:
return false;
case TST_decltype:
case TST_typeofExpr:
if (Expr *E = DS.getRepAsExpr())
return E->getType()->isFunctionType();
return false;
case TST_underlyingType:
case TST_typename:
case TST_typeofType: {
QualType QT = DS.getRepAsType().get();
if (QT.isNull())
return false;
if (const LocInfoType *LIT = dyn_cast<LocInfoType>(QT))
QT = LIT->getType();
if (QT.isNull())
return false;
return QT->isFunctionType();
}
}
return false;
}
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
/// declaration specifier includes.
///

View File

@ -1,8 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify %s
class A {
virtual void f();
virtual void g() = 0;
virtual void g() = 0; // expected-note{{unimplemented pure virtual method 'g' in 'A'}}
void h() = 0; // expected-error {{'h' is not virtual and cannot be declared pure}}
void i() = 1; // expected-error {{initializer on function does not look like a pure-specifier}}
@ -19,20 +19,26 @@ virtual void A::k() { } // expected-error{{'virtual' can only be specified insid
class B : public A {
// Needs to recognize that overridden function is virtual.
//void g() = 0;
void g() = 0;
// Needs to recognize that function does not override.
//void g(int) = 0;
void g(int) = 0; // expected-error{{'g' is not virtual and cannot be declared pure}}
};
// Needs to recognize invalid uses of abstract classes.
/*
A fn(A)
A fn(A) // expected-error{{parameter type 'A' is an abstract class}} \
// expected-error{{return type 'A' is an abstract class}}
{
A a;
static_cast<A>(0);
A a; // expected-error{{variable type 'A' is an abstract class}}
(void)static_cast<A>(0);
try {
} catch(A) {
} catch(A) { // expected-error{{variable type 'A' is an abstract class}}
}
}
*/
namespace rdar9670557 {
typedef int func(int);
struct X {
virtual func f = 0;
};
}