#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/Compiler.h"
using namespace clang;
//===----------------------------------------------------------------------===/
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
+namespace {
+ class VISIBILITY_HIDDEN TemplateTypeInstantiator {
+ Sema &SemaRef;
+ const TemplateArgument *TemplateArgs;
+ unsigned NumTemplateArgs;
+ SourceLocation Loc;
+ DeclarationName Entity;
+
+ public:
+ TemplateTypeInstantiator(Sema &SemaRef,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation Loc,
+ DeclarationName Entity)
+ : SemaRef(SemaRef), TemplateArgs(TemplateArgs),
+ NumTemplateArgs(NumTemplateArgs), Loc(Loc), Entity(Entity) { }
+
+ QualType operator()(QualType T) const { return Instantiate(T); }
+
+ QualType Instantiate(QualType T) const;
+
+ // Declare instantiate functions for each type.
+#define TYPE(Class, Base) \
+ QualType Instantiate##Class##Type(const Class##Type *T, \
+ unsigned Quals) const;
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ };
+}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ExtQualType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate ExtQualType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const BuiltinType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T,
+ unsigned Quals) const {
assert(false && "BuiltinType is never dependent and cannot be instantiated");
- return QualType(T, CVR);
+ return QualType(T, Quals);
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const FixedWidthIntType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::
+InstantiateFixedWidthIntType(const FixedWidthIntType *T, unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate FixedWidthIntType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ComplexType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate ComplexType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const PointerType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate PointerType yet");
- return QualType();
+QualType
+TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T,
+ unsigned Quals) const {
+ QualType PointeeType = Instantiate(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ return SemaRef.BuildPointerType(PointeeType, Quals, Loc, Entity);
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const BlockPointerType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateBlockPointerType(const BlockPointerType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate BlockPointerType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ReferenceType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ReferenceType yet");
- return QualType();
+QualType
+TemplateTypeInstantiator::InstantiateReferenceType(const ReferenceType *T,
+ unsigned Quals) const {
+ QualType ReferentType = Instantiate(T->getPointeeType());
+ if (ReferentType.isNull())
+ return QualType();
+
+ return SemaRef.BuildReferenceType(ReferentType, Quals, Loc, Entity);
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const MemberPointerType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::
+InstantiateMemberPointerType(const MemberPointerType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate MemberPointerType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ConstantArrayType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ConstantArrayType yet");
- return QualType();
+QualType
+TemplateTypeInstantiator::
+InstantiateConstantArrayType(const ConstantArrayType *T,
+ unsigned Quals) const {
+ QualType ElementType = Instantiate(T->getElementType());
+ if (ElementType.isNull())
+ return ElementType;
+
+ // Build a temporary integer literal to specify the size for
+ // BuildArrayType. Since we have already checked the size as part of
+ // creating the dependent array type in the first place, we know
+ // there aren't any errors.
+ IntegerLiteral ArraySize(T->getSize(), SemaRef.Context.IntTy, Loc);
+ return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
+ &ArraySize, T->getIndexTypeQualifier(),
+ Loc, Entity);
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const IncompleteArrayType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate IncompleteArrayType yet");
- return QualType();
+QualType
+TemplateTypeInstantiator::
+InstantiateIncompleteArrayType(const IncompleteArrayType *T,
+ unsigned Quals) const {
+ QualType ElementType = Instantiate(T->getElementType());
+ if (ElementType.isNull())
+ return ElementType;
+
+ return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
+ 0, T->getIndexTypeQualifier(),
+ Loc, Entity);
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const VariableArrayType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::
+InstantiateVariableArrayType(const VariableArrayType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate VariableArrayType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const DependentSizedArrayType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::
+InstantiateDependentSizedArrayType(const DependentSizedArrayType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate DependentSizedArrayType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const VectorType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate VectorType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ExtVectorType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateExtVectorType(const ExtVectorType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate ExtVectorType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const FunctionProtoType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::
+InstantiateFunctionProtoType(const FunctionProtoType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate FunctionProtoType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const FunctionNoProtoType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::
+InstantiateFunctionNoProtoType(const FunctionNoProtoType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate FunctionNoProtoType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const TypedefType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate TypedefType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const TypeOfExprType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateTypeOfExprType(const TypeOfExprType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate TypeOfExprType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const TypeOfType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate TypeOfType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const RecordType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate RecordType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const CXXRecordType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateCXXRecordType(const CXXRecordType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate CXXRecordType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const EnumType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate EnumType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const TemplateTypeParmType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::
+InstantiateTemplateTypeParmType(const TemplateTypeParmType *T,
+ unsigned Quals) const {
if (T->getDepth() == 0) {
// Replace the template type parameter with its corresponding
// template argument.
assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type &&
"Template argument kind mismatch");
QualType Result = TemplateArgs[T->getIndex()].getAsType();
- if (Result.isNull() || !CVR)
+ if (Result.isNull() || !Quals)
return Result;
// C++ [dcl.ref]p1:
// the cv-qualifiers are introduced through the use of a
// typedef (7.1.3) or of a template type argument (14.3), in
// which case the cv-qualifiers are ignored.
- if (CVR && Result->isReferenceType())
- CVR = 0;
+ if (Quals && Result->isReferenceType())
+ Quals = 0;
- return QualType(Result.getTypePtr(), CVR | Result.getCVRQualifiers());
+ return QualType(Result.getTypePtr(), Quals | Result.getCVRQualifiers());
}
// The template type parameter comes from an inner template (e.g.,
// parameter with the template "level" reduced by one.
return SemaRef.Context.getTemplateTypeParmType(T->getDepth() - 1,
T->getIndex(),
- T->getName());
+ T->getName())
+ .getQualifiedType(Quals);
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ClassTemplateSpecializationType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
+QualType
+TemplateTypeInstantiator::
+InstantiateClassTemplateSpecializationType(
+ const ClassTemplateSpecializationType *T,
+ unsigned Quals) const {
// FIXME: Implement this
assert(false && "Cannot instantiate ClassTemplateSpecializationType yet");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ObjCInterfaceType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ObjCInterfaceType yet");
+QualType
+TemplateTypeInstantiator::
+InstantiateObjCInterfaceType(const ObjCInterfaceType *T,
+ unsigned Quals) const {
+ assert(false && "Objective-C types cannot be dependent");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ObjCQualifiedInterfaceType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ObjCQualifiedInterfaceType yet");
+QualType
+TemplateTypeInstantiator::
+InstantiateObjCQualifiedInterfaceType(const ObjCQualifiedInterfaceType *T,
+ unsigned Quals) const {
+ assert(false && "Objective-C types cannot be dependent");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ObjCQualifiedIdType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ObjCQualifiedIdType yet");
+QualType
+TemplateTypeInstantiator::
+InstantiateObjCQualifiedIdType(const ObjCQualifiedIdType *T,
+ unsigned Quals) const {
+ assert(false && "Objective-C types cannot be dependent");
return QualType();
}
-static QualType PerformTypeInstantiation(Sema &SemaRef,
- const ObjCQualifiedClassType *T,
- unsigned CVR,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ObjCQualifiedClassType yet");
+QualType
+TemplateTypeInstantiator::
+InstantiateObjCQualifiedClassType(const ObjCQualifiedClassType *T,
+ unsigned Quals) const {
+ assert(false && "Objective-C types cannot be dependent");
return QualType();
}
+/// \brief The actual implementation of Sema::InstantiateType().
+QualType TemplateTypeInstantiator::Instantiate(QualType T) const {
+ // If T is not a dependent type, there is nothing to do.
+ if (!T->isDependentType())
+ return T;
+
+ switch (T->getTypeClass()) {
+#define TYPE(Class, Base) \
+ case Type::Class: \
+ return Instantiate##Class##Type(cast<Class##Type>(T.getTypePtr()), \
+ T.getCVRQualifiers());
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ }
+
+ assert(false && "Not all types have been decoded for instantiation");
+ return QualType();
+}
/// \brief Instantiate the type T with a given set of template arguments.
///
if (!T->isDependentType())
return T;
- switch (T->getTypeClass()) {
-#define TYPE(Class, Base) \
- case Type::Class: \
- return PerformTypeInstantiation(*this, \
- cast<Class##Type>(T.getTypePtr()), \
- T.getCVRQualifiers(), TemplateArgs, \
- NumTemplateArgs, Loc, Entity);
-#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
- }
-
- assert(false && "Not all types have been decoded for instantiation");
- return QualType();
+ TemplateTypeInstantiator Instantiator(*this, TemplateArgs, NumTemplateArgs,
+ Loc, Entity);
+ return Instantiator(T);
}
return Result;
}
+static std::string getPrintableNameForEntity(DeclarationName Entity) {
+ if (Entity)
+ return Entity.getAsString();
+
+ return "type name";
+}
+
+/// \brief Build a pointer type.
+///
+/// \param T The type to which we'll be building a pointer.
+///
+/// \param Quals The cvr-qualifiers to be applied to the pointer type.
+///
+/// \param Loc The location of the entity whose type involves this
+/// pointer type or, if there is no such entity, the location of the
+/// type that will have pointer type.
+///
+/// \param Entity The name of the entity that involves the pointer
+/// type, if known.
+///
+/// \returns A suitable pointer type, if there are no
+/// errors. Otherwise, returns a NULL type.
+QualType Sema::BuildPointerType(QualType T, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity) {
+ if (T->isReferenceType()) {
+ // C++ 8.3.2p4: There shall be no ... pointers to references ...
+ Diag(Loc, diag::err_illegal_decl_pointer_to_reference)
+ << getPrintableNameForEntity(Entity);
+ return QualType();
+ }
+
+ // Enforce C99 6.7.3p2: "Types other than pointer types derived from
+ // object or incomplete types shall not be restrict-qualified."
+ if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+ Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
+ << T;
+ Quals &= ~QualType::Restrict;
+ }
+
+ // Build the pointer type.
+ return Context.getPointerType(T).getQualifiedType(Quals);
+}
+
+/// \brief Build a reference type.
+///
+/// \param T The type to which we'll be building a reference.
+///
+/// \param Quals The cvr-qualifiers to be applied to the reference type.
+///
+/// \param Loc The location of the entity whose type involves this
+/// reference type or, if there is no such entity, the location of the
+/// type that will have reference type.
+///
+/// \param Entity The name of the entity that involves the reference
+/// type, if known.
+///
+/// \returns A suitable reference type, if there are no
+/// errors. Otherwise, returns a NULL type.
+QualType Sema::BuildReferenceType(QualType T, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity) {
+ if (T->isReferenceType()) {
+ // C++ [dcl.ref]p4: There shall be no references to references.
+ //
+ // According to C++ DR 106, references to references are only
+ // diagnosed when they are written directly (e.g., "int & &"),
+ // but not when they happen via a typedef:
+ //
+ // typedef int& intref;
+ // typedef intref& intref2;
+ //
+ // Parser::ParserDeclaratorInternal diagnoses the case where
+ // references are written directly; here, we handle the
+ // collapsing of references-to-references as described in C++
+ // DR 106 and amended by C++ DR 540.
+ return T;
+ }
+
+ // C++ [dcl.ref]p1:
+ // A declarator that specifies the type “reference to cv void”
+ // is ill-formed.
+ if (T->isVoidType()) {
+ Diag(Loc, diag::err_reference_to_void);
+ return QualType();
+ }
+
+ // Enforce C99 6.7.3p2: "Types other than pointer types derived from
+ // object or incomplete types shall not be restrict-qualified."
+ if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+ Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
+ << T;
+ Quals &= ~QualType::Restrict;
+ }
+
+ // C++ [dcl.ref]p1:
+ // [...] Cv-qualified references are ill-formed except when the
+ // cv-qualifiers are introduced through the use of a typedef
+ // (7.1.3) or of a template type argument (14.3), in which case
+ // the cv-qualifiers are ignored.
+ //
+ // We diagnose extraneous cv-qualifiers for the non-typedef,
+ // non-template type argument case within the parser. Here, we just
+ // ignore any extraneous cv-qualifiers.
+ Quals &= ~QualType::Const;
+ Quals &= ~QualType::Volatile;
+
+ // Handle restrict on references.
+ return Context.getReferenceType(T).getQualifiedType(Quals);
+}
+
+/// \brief Build an array type.
+///
+/// \param T The type of each element in the array.
+///
+/// \param ASM C99 array size modifier (e.g., '*', 'static').
+///
+/// \param ArraySize Expression describing the size of the array.
+///
+/// \param Quals The cvr-qualifiers to be applied to the array's
+/// element type.
+///
+/// \param Loc The location of the entity whose type involves this
+/// array type or, if there is no such entity, the location of the
+/// type that will have array type.
+///
+/// \param Entity The name of the entity that involves the array
+/// type, if known.
+///
+/// \returns A suitable array type, if there are no errors. Otherwise,
+/// returns a NULL type.
+QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
+ Expr *ArraySize, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity) {
+ // C99 6.7.5.2p1: If the element type is an incomplete or function type,
+ // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
+ if (DiagnoseIncompleteType(Loc, T,
+ diag::err_illegal_decl_array_incomplete_type))
+ return QualType();
+
+ if (T->isFunctionType()) {
+ Diag(Loc, diag::err_illegal_decl_array_of_functions)
+ << getPrintableNameForEntity(Entity);
+ return QualType();
+ }
+
+ // C++ 8.3.2p4: There shall be no ... arrays of references ...
+ if (T->isReferenceType()) {
+ Diag(Loc, diag::err_illegal_decl_array_of_references)
+ << getPrintableNameForEntity(Entity);
+ return QualType();
+ }
+
+ if (const RecordType *EltTy = T->getAsRecordType()) {
+ // If the element type is a struct or union that contains a variadic
+ // array, accept it as a GNU extension: C99 6.7.2.1p2.
+ if (EltTy->getDecl()->hasFlexibleArrayMember())
+ Diag(Loc, diag::ext_flexible_array_in_array) << T;
+ } else if (T->isObjCInterfaceType()) {
+ Diag(Loc, diag::warn_objc_array_of_interfaces) << T;
+ }
+
+ // C99 6.7.5.2p1: The size expression shall have integer type.
+ if (ArraySize && !ArraySize->isTypeDependent() &&
+ !ArraySize->getType()->isIntegerType()) {
+ Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
+ << ArraySize->getType() << ArraySize->getSourceRange();
+ ArraySize->Destroy(Context);
+ return QualType();
+ }
+ llvm::APSInt ConstVal(32);
+ if (!ArraySize) {
+ T = Context.getIncompleteArrayType(T, ASM, Quals);
+ } else if (ArraySize->isValueDependent()) {
+ T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals);
+ } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
+ (!T->isDependentType() && !T->isConstantSizeType())) {
+ // Per C99, a variable array is an array with either a non-constant
+ // size or an element type that has a non-constant-size
+ T = Context.getVariableArrayType(T, ArraySize, ASM, Quals);
+ } else {
+ // C99 6.7.5.2p1: If the expression is a constant expression, it shall
+ // have a value greater than zero.
+ if (ConstVal.isSigned()) {
+ if (ConstVal.isNegative()) {
+ Diag(ArraySize->getLocStart(),
+ diag::err_typecheck_negative_array_size)
+ << ArraySize->getSourceRange();
+ return QualType();
+ } else if (ConstVal == 0) {
+ // GCC accepts zero sized static arrays.
+ Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
+ << ArraySize->getSourceRange();
+ }
+ }
+ T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
+ }
+ // If this is not C99, extwarn about VLA's and C99 array size modifiers.
+ if (!getLangOptions().C99) {
+ if (ArraySize && !ArraySize->isTypeDependent() &&
+ !ArraySize->isValueDependent() &&
+ !ArraySize->isIntegerConstantExpr(Context))
+ Diag(Loc, diag::ext_vla);
+ else if (ASM != ArrayType::Normal || Quals != 0)
+ Diag(Loc, diag::ext_c99_array_usage);
+ }
+
+ return T;
+}
+
+
/// GetTypeForDeclarator - Convert the type for the specified
/// declarator to Type instances. Skip the outermost Skip type
/// objects.
break;
}
+ // The name we're declaring, if any.
+ DeclarationName Name;
+ if (D.getIdentifier())
+ Name = D.getIdentifier();
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
T = Context.getBlockPointerType(T);
break;
case DeclaratorChunk::Pointer:
- if (T->isReferenceType()) {
- // C++ 8.3.2p4: There shall be no ... pointers to references ...
- Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference)
- << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
- D.setInvalidType(true);
- T = Context.IntTy;
- }
-
- // Enforce C99 6.7.3p2: "Types other than pointer types derived from
- // object or incomplete types shall not be restrict-qualified."
- if ((DeclType.Ptr.TypeQuals & QualType::Restrict) &&
- !T->isIncompleteOrObjectType()) {
- Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
- << T;
- DeclType.Ptr.TypeQuals &= ~QualType::Restrict;
- }
-
- // Apply the pointer typequals to the pointer object.
- T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals);
+ T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
break;
- case DeclaratorChunk::Reference: {
- // Whether we should suppress the creation of the reference.
- bool SuppressReference = false;
- if (T->isReferenceType()) {
- // C++ [dcl.ref]p4: There shall be no references to references.
- //
- // According to C++ DR 106, references to references are only
- // diagnosed when they are written directly (e.g., "int & &"),
- // but not when they happen via a typedef:
- //
- // typedef int& intref;
- // typedef intref& intref2;
- //
- // Parser::ParserDeclaratorInternal diagnoses the case where
- // references are written directly; here, we handle the
- // collapsing of references-to-references as described in C++
- // DR 106 and amended by C++ DR 540.
- SuppressReference = true;
- }
-
- // C++ [dcl.ref]p1:
- // A declarator that specifies the type “reference to cv void”
- // is ill-formed.
- if (T->isVoidType()) {
- Diag(DeclType.Loc, diag::err_reference_to_void);
- D.setInvalidType(true);
- T = Context.IntTy;
- }
-
- // Enforce C99 6.7.3p2: "Types other than pointer types derived from
- // object or incomplete types shall not be restrict-qualified."
- if (DeclType.Ref.HasRestrict &&
- !T->isIncompleteOrObjectType()) {
- Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
- << T;
- DeclType.Ref.HasRestrict = false;
- }
-
- if (!SuppressReference)
- T = Context.getReferenceType(T);
-
- // Handle restrict on references.
- if (DeclType.Ref.HasRestrict)
- T.addRestrict();
+ case DeclaratorChunk::Reference:
+ T = BuildReferenceType(T,
+ DeclType.Ref.HasRestrict? QualType::Restrict : 0,
+ DeclType.Loc, Name);
break;
- }
case DeclaratorChunk::Array: {
DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
Expr *ArraySize = static_cast<Expr*>(ATI.NumElts);
ASM = ArrayType::Static;
else
ASM = ArrayType::Normal;
-
- // C99 6.7.5.2p1: If the element type is an incomplete or function type,
- // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
- if (DiagnoseIncompleteType(D.getIdentifierLoc(), T,
- diag::err_illegal_decl_array_incomplete_type)) {
- T = Context.IntTy;
- D.setInvalidType(true);
- } else if (T->isFunctionType()) {
- Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_functions)
- << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
- T = Context.getPointerType(T);
- D.setInvalidType(true);
- } else if (const ReferenceType *RT = T->getAsReferenceType()) {
- // C++ 8.3.2p4: There shall be no ... arrays of references ...
- Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_references)
- << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
- T = RT->getPointeeType();
- D.setInvalidType(true);
- } else if (const RecordType *EltTy = T->getAsRecordType()) {
- // If the element type is a struct or union that contains a variadic
- // array, accept it as a GNU extension: C99 6.7.2.1p2.
- if (EltTy->getDecl()->hasFlexibleArrayMember())
- Diag(DeclType.Loc, diag::ext_flexible_array_in_array) << T;
- } else if (T->isObjCInterfaceType()) {
- Diag(DeclType.Loc, diag::warn_objc_array_of_interfaces) << T;
- }
-
- // C99 6.7.5.2p1: The size expression shall have integer type.
- if (ArraySize && !ArraySize->getType()->isIntegerType()) {
- Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
- << ArraySize->getType() << ArraySize->getSourceRange();
- D.setInvalidType(true);
- ArraySize->Destroy(Context);
- ATI.NumElts = ArraySize = 0;
- }
- llvm::APSInt ConstVal(32);
- if (!ArraySize) {
- T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals);
- } else if (ArraySize->isValueDependent()) {
- T = Context.getDependentSizedArrayType(T, ArraySize, ASM, ATI.TypeQuals);
- } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
- !T->isConstantSizeType()) {
- // Per C99, a variable array is an array with either a non-constant
- // size or an element type that has a non-constant-size
- T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals);
- } else {
- // C99 6.7.5.2p1: If the expression is a constant expression, it shall
- // have a value greater than zero.
- if (ConstVal.isSigned()) {
- if (ConstVal.isNegative()) {
- Diag(ArraySize->getLocStart(),
- diag::err_typecheck_negative_array_size)
- << ArraySize->getSourceRange();
- D.setInvalidType(true);
- } else if (ConstVal == 0) {
- // GCC accepts zero sized static arrays.
- Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
- << ArraySize->getSourceRange();
- }
- }
- T = Context.getConstantArrayType(T, ConstVal, ASM, ATI.TypeQuals);
- }
- // If this is not C99, extwarn about VLA's and C99 array size modifiers.
- if (!getLangOptions().C99) {
- if (ArraySize && !ArraySize->isValueDependent() &&
- !ArraySize->isIntegerConstantExpr(Context))
- Diag(D.getIdentifierLoc(), diag::ext_vla);
- else if (ASM != ArrayType::Normal || ATI.TypeQuals != 0)
- Diag(D.getIdentifierLoc(), diag::ext_c99_array_usage);
- }
+ T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name);
break;
}
case DeclaratorChunk::Function: {
break;
}
+ if (T.isNull()) {
+ D.setInvalidType(true);
+ T = Context.IntTy;
+ }
+
// See if there are any attributes on this declarator chunk.
if (const AttributeList *AL = DeclType.getAttrs())
ProcessTypeAttributeList(T, AL);