2007-07-11 21:01:13 +04:00
|
|
|
//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 22:59:25 +03:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-07-11 21:01:13 +04:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements type-related semantic analysis.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Sema.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2007-10-01 23:00:59 +04:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-03-03 07:44:36 +03:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2008-08-11 08:54:23 +04:00
|
|
|
#include "clang/AST/Expr.h"
|
2008-08-11 07:45:03 +04:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-03-24 02:06:20 +03:00
|
|
|
/// \brief Perform adjustment on the parameter type of a function.
|
|
|
|
///
|
|
|
|
/// This routine adjusts the given parameter type @p T to the actual
|
|
|
|
/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
|
|
|
|
/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
|
|
|
|
QualType Sema::adjustParameterType(QualType T) {
|
|
|
|
// C99 6.7.5.3p7:
|
|
|
|
if (T->isArrayType()) {
|
|
|
|
// C99 6.7.5.3p7:
|
|
|
|
// A declaration of a parameter as "array of type" shall be
|
|
|
|
// adjusted to "qualified pointer to type", where the type
|
|
|
|
// qualifiers (if any) are those specified within the [ and ] of
|
|
|
|
// the array type derivation.
|
|
|
|
return Context.getArrayDecayedType(T);
|
|
|
|
} else if (T->isFunctionType())
|
|
|
|
// C99 6.7.5.3p8:
|
|
|
|
// A declaration of a parameter as "function returning type"
|
|
|
|
// shall be adjusted to "pointer to function returning type", as
|
|
|
|
// in 6.3.2.1.
|
|
|
|
return Context.getPointerType(T);
|
|
|
|
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
2009-01-31 01:09:00 +03:00
|
|
|
/// \brief Convert the specified declspec to the appropriate type
|
|
|
|
/// object.
|
|
|
|
/// \param DS the declaration specifiers
|
2009-04-22 09:27:59 +04:00
|
|
|
/// \param DeclLoc The location of the declarator identifier or invalid if none.
|
2009-04-25 12:47:54 +04:00
|
|
|
/// \returns The type described by the declaration specifiers. This function
|
|
|
|
/// never returns null.
|
2009-04-22 09:27:59 +04:00
|
|
|
QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
|
2009-04-25 12:06:05 +04:00
|
|
|
SourceLocation DeclLoc,
|
|
|
|
bool &isInvalid) {
|
2007-07-11 21:01:13 +04:00
|
|
|
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
|
|
|
|
// checking.
|
2008-02-21 00:40:32 +03:00
|
|
|
QualType Result;
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
switch (DS.getTypeSpecType()) {
|
2008-04-02 10:50:17 +04:00
|
|
|
case DeclSpec::TST_void:
|
|
|
|
Result = Context.VoidTy;
|
|
|
|
break;
|
2007-07-11 21:01:13 +04:00
|
|
|
case DeclSpec::TST_char:
|
|
|
|
if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)
|
2008-02-21 02:53:49 +03:00
|
|
|
Result = Context.CharTy;
|
2007-07-11 21:01:13 +04:00
|
|
|
else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed)
|
2008-02-21 02:53:49 +03:00
|
|
|
Result = Context.SignedCharTy;
|
2007-07-11 21:01:13 +04:00
|
|
|
else {
|
|
|
|
assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
|
|
|
|
"Unknown TSS value");
|
2008-02-21 02:53:49 +03:00
|
|
|
Result = Context.UnsignedCharTy;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-02-21 00:40:32 +03:00
|
|
|
break;
|
2008-08-09 20:51:54 +04:00
|
|
|
case DeclSpec::TST_wchar:
|
|
|
|
if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)
|
|
|
|
Result = Context.WCharTy;
|
|
|
|
else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) {
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
|
|
|
|
<< DS.getSpecifierName(DS.getTypeSpecType());
|
2008-08-09 20:51:54 +04:00
|
|
|
Result = Context.getSignedWCharType();
|
|
|
|
} else {
|
|
|
|
assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
|
|
|
|
"Unknown TSS value");
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
|
|
|
|
<< DS.getSpecifierName(DS.getTypeSpecType());
|
2008-08-09 20:51:54 +04:00
|
|
|
Result = Context.getUnsignedWCharType();
|
|
|
|
}
|
|
|
|
break;
|
2008-04-05 10:32:51 +04:00
|
|
|
case DeclSpec::TST_unspecified:
|
2008-07-26 04:46:50 +04:00
|
|
|
// "<proto1,proto2>" is an objc qualified ID with a missing id.
|
2008-10-20 06:01:50 +04:00
|
|
|
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
|
2008-07-26 05:53:50 +04:00
|
|
|
Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ,
|
2008-07-26 04:46:50 +04:00
|
|
|
DS.getNumProtocolQualifiers());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-04-05 10:32:51 +04:00
|
|
|
// Unspecified typespec defaults to int in C90. However, the C90 grammar
|
|
|
|
// [C90 6.5] only allows a decl-spec if there was *some* type-specifier,
|
|
|
|
// type-qualifier, or storage-class-specifier. If not, emit an extwarn.
|
|
|
|
// Note that the one exception to this is function definitions, which are
|
|
|
|
// allowed to be completely missing a declspec. This is handled in the
|
|
|
|
// parser already though by it pretending to have seen an 'int' in this
|
|
|
|
// case.
|
|
|
|
if (getLangOptions().ImplicitInt) {
|
2009-02-27 21:53:28 +03:00
|
|
|
// In C89 mode, we only warn if there is a completely missing declspec
|
|
|
|
// when one is not allowed.
|
2009-04-22 09:27:59 +04:00
|
|
|
if (DS.isEmpty()) {
|
|
|
|
if (DeclLoc.isInvalid())
|
|
|
|
DeclLoc = DS.getSourceRange().getBegin();
|
|
|
|
Diag(DeclLoc, diag::warn_missing_declspec)
|
|
|
|
<< DS.getSourceRange()
|
2009-02-28 01:31:56 +03:00
|
|
|
<< CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(),
|
|
|
|
"int");
|
2009-04-22 09:27:59 +04:00
|
|
|
}
|
2009-02-17 01:38:20 +03:00
|
|
|
} else if (!DS.hasTypeSpecifier()) {
|
2008-04-05 10:32:51 +04:00
|
|
|
// C99 and C++ require a type specifier. For example, C99 6.7.2p2 says:
|
|
|
|
// "At least one type specifier shall be given in the declaration
|
|
|
|
// specifiers in each declaration, and in the specifier-qualifier list in
|
|
|
|
// each struct declaration and type name."
|
2009-02-17 01:38:20 +03:00
|
|
|
// FIXME: Does Microsoft really have the implicit int extension in C++?
|
2009-04-22 09:27:59 +04:00
|
|
|
if (DeclLoc.isInvalid())
|
|
|
|
DeclLoc = DS.getSourceRange().getBegin();
|
|
|
|
|
|
|
|
if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft)
|
|
|
|
Diag(DeclLoc, diag::err_missing_type_specifier)
|
|
|
|
<< DS.getSourceRange();
|
|
|
|
else
|
|
|
|
Diag(DeclLoc, diag::warn_missing_type_specifier)
|
|
|
|
<< DS.getSourceRange();
|
2009-03-27 08:10:56 +03:00
|
|
|
|
|
|
|
// FIXME: If we could guarantee that the result would be
|
|
|
|
// well-formed, it would be useful to have a code insertion hint
|
|
|
|
// here. However, after emitting this warning/error, we often
|
|
|
|
// emit other errors.
|
2008-04-05 10:32:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// FALL THROUGH.
|
2007-08-21 21:02:28 +04:00
|
|
|
case DeclSpec::TST_int: {
|
2007-07-11 21:01:13 +04:00
|
|
|
if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) {
|
|
|
|
switch (DS.getTypeSpecWidth()) {
|
2008-02-21 02:53:49 +03:00
|
|
|
case DeclSpec::TSW_unspecified: Result = Context.IntTy; break;
|
|
|
|
case DeclSpec::TSW_short: Result = Context.ShortTy; break;
|
|
|
|
case DeclSpec::TSW_long: Result = Context.LongTy; break;
|
|
|
|
case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (DS.getTypeSpecWidth()) {
|
2008-02-21 02:53:49 +03:00
|
|
|
case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break;
|
|
|
|
case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break;
|
|
|
|
case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break;
|
|
|
|
case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
2008-02-21 00:40:32 +03:00
|
|
|
break;
|
2007-08-21 21:02:28 +04:00
|
|
|
}
|
2008-02-21 02:53:49 +03:00
|
|
|
case DeclSpec::TST_float: Result = Context.FloatTy; break;
|
2008-02-21 00:40:32 +03:00
|
|
|
case DeclSpec::TST_double:
|
|
|
|
if (DS.getTypeSpecWidth() == DeclSpec::TSW_long)
|
2008-02-21 02:53:49 +03:00
|
|
|
Result = Context.LongDoubleTy;
|
2008-02-21 00:40:32 +03:00
|
|
|
else
|
2008-02-21 02:53:49 +03:00
|
|
|
Result = Context.DoubleTy;
|
2008-02-21 00:40:32 +03:00
|
|
|
break;
|
2008-02-21 02:53:49 +03:00
|
|
|
case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool
|
2007-07-11 21:01:13 +04:00
|
|
|
case DeclSpec::TST_decimal32: // _Decimal32
|
|
|
|
case DeclSpec::TST_decimal64: // _Decimal64
|
|
|
|
case DeclSpec::TST_decimal128: // _Decimal128
|
2009-05-13 09:02:08 +04:00
|
|
|
Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported);
|
|
|
|
Result = Context.IntTy;
|
|
|
|
isInvalid = true;
|
|
|
|
break;
|
2008-04-13 22:59:07 +04:00
|
|
|
case DeclSpec::TST_class:
|
2007-07-11 21:01:13 +04:00
|
|
|
case DeclSpec::TST_enum:
|
|
|
|
case DeclSpec::TST_union:
|
|
|
|
case DeclSpec::TST_struct: {
|
|
|
|
Decl *D = static_cast<Decl *>(DS.getTypeRep());
|
2008-04-13 22:59:07 +04:00
|
|
|
assert(D && "Didn't get a decl for a class/enum/union/struct?");
|
2007-07-11 21:01:13 +04:00
|
|
|
assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
|
|
|
|
DS.getTypeSpecSign() == 0 &&
|
|
|
|
"Can't handle qualifiers on typedef names yet!");
|
|
|
|
// TypeQuals handled by caller.
|
2008-04-14 01:07:44 +04:00
|
|
|
Result = Context.getTypeDeclType(cast<TypeDecl>(D));
|
2009-04-25 12:47:54 +04:00
|
|
|
|
|
|
|
if (D->isInvalidDecl())
|
|
|
|
isInvalid = true;
|
2008-02-21 00:40:32 +03:00
|
|
|
break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2009-02-09 18:09:02 +03:00
|
|
|
case DeclSpec::TST_typename: {
|
2007-07-11 21:01:13 +04:00
|
|
|
assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
|
|
|
|
DS.getTypeSpecSign() == 0 &&
|
|
|
|
"Can't handle qualifiers on typedef names yet!");
|
2009-02-09 18:09:02 +03:00
|
|
|
Result = QualType::getFromOpaquePtr(DS.getTypeRep());
|
2008-04-14 01:07:44 +04:00
|
|
|
|
2009-02-09 18:09:02 +03:00
|
|
|
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
|
|
|
|
// FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so
|
|
|
|
// we have this "hack" for now...
|
|
|
|
if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType())
|
|
|
|
Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(),
|
|
|
|
(ObjCProtocolDecl**)PQ,
|
|
|
|
DS.getNumProtocolQualifiers());
|
|
|
|
else if (Result == Context.getObjCIdType())
|
2008-07-26 05:53:50 +04:00
|
|
|
// id<protocol-list>
|
|
|
|
Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ,
|
|
|
|
DS.getNumProtocolQualifiers());
|
2009-04-22 09:27:59 +04:00
|
|
|
else if (Result == Context.getObjCClassType()) {
|
|
|
|
if (DeclLoc.isInvalid())
|
|
|
|
DeclLoc = DS.getSourceRange().getBegin();
|
2009-02-23 21:53:24 +03:00
|
|
|
// Class<protocol-list>
|
2009-04-22 09:27:59 +04:00
|
|
|
Diag(DeclLoc, diag::err_qualified_class_unsupported)
|
|
|
|
<< DS.getSourceRange();
|
|
|
|
} else {
|
|
|
|
if (DeclLoc.isInvalid())
|
|
|
|
DeclLoc = DS.getSourceRange().getBegin();
|
|
|
|
Diag(DeclLoc, diag::err_invalid_protocol_qualifiers)
|
|
|
|
<< DS.getSourceRange();
|
2009-04-25 12:06:05 +04:00
|
|
|
isInvalid = true;
|
2009-04-22 09:27:59 +04:00
|
|
|
}
|
2007-12-18 00:03:50 +03:00
|
|
|
}
|
2009-04-25 12:06:05 +04:00
|
|
|
|
|
|
|
// If this is a reference to an invalid typedef, propagate the invalidity.
|
|
|
|
if (TypedefType *TDT = dyn_cast<TypedefType>(Result))
|
|
|
|
if (TDT->getDecl()->isInvalidDecl())
|
|
|
|
isInvalid = true;
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// TypeQuals handled by caller.
|
2008-02-21 00:40:32 +03:00
|
|
|
break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-02-21 00:40:32 +03:00
|
|
|
case DeclSpec::TST_typeofType:
|
|
|
|
Result = QualType::getFromOpaquePtr(DS.getTypeRep());
|
|
|
|
assert(!Result.isNull() && "Didn't get a type for typeof?");
|
2007-07-31 16:34:36 +04:00
|
|
|
// TypeQuals handled by caller.
|
2008-02-21 02:53:49 +03:00
|
|
|
Result = Context.getTypeOfType(Result);
|
2008-02-21 00:40:32 +03:00
|
|
|
break;
|
2007-07-31 16:34:36 +04:00
|
|
|
case DeclSpec::TST_typeofExpr: {
|
|
|
|
Expr *E = static_cast<Expr *>(DS.getTypeRep());
|
|
|
|
assert(E && "Didn't get an expression for typeof?");
|
|
|
|
// TypeQuals handled by caller.
|
2009-02-27 02:50:07 +03:00
|
|
|
Result = Context.getTypeOfExprType(E);
|
2008-02-21 00:40:32 +03:00
|
|
|
break;
|
2007-07-31 16:34:36 +04:00
|
|
|
}
|
2009-02-18 20:45:20 +03:00
|
|
|
case DeclSpec::TST_error:
|
2009-04-25 12:47:54 +04:00
|
|
|
Result = Context.IntTy;
|
|
|
|
isInvalid = true;
|
|
|
|
break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-02-21 00:40:32 +03:00
|
|
|
|
|
|
|
// Handle complex types.
|
2009-02-15 00:06:05 +03:00
|
|
|
if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) {
|
|
|
|
if (getLangOptions().Freestanding)
|
|
|
|
Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex);
|
2008-02-21 02:53:49 +03:00
|
|
|
Result = Context.getComplexType(Result);
|
2009-02-15 00:06:05 +03:00
|
|
|
}
|
2008-02-21 00:40:32 +03:00
|
|
|
|
|
|
|
assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary &&
|
|
|
|
"FIXME: imaginary types not supported yet!");
|
|
|
|
|
2008-02-21 01:04:11 +03:00
|
|
|
// See if there are any attributes on the declspec that apply to the type (as
|
|
|
|
// opposed to the decl).
|
2008-06-26 10:27:57 +04:00
|
|
|
if (const AttributeList *AL = DS.getAttributes())
|
2008-06-29 04:50:08 +04:00
|
|
|
ProcessTypeAttributeList(Result, AL);
|
2008-02-21 04:07:18 +03:00
|
|
|
|
2008-04-02 10:50:17 +04:00
|
|
|
// Apply const/volatile/restrict qualifiers to T.
|
|
|
|
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
|
|
|
|
|
|
|
|
// Enforce C99 6.7.3p2: "Types other than pointer types derived from object
|
|
|
|
// or incomplete types shall not be restrict-qualified." C++ also allows
|
|
|
|
// restrict-qualified references.
|
|
|
|
if (TypeQuals & QualType::Restrict) {
|
2009-02-26 22:13:44 +03:00
|
|
|
if (Result->isPointerType() || Result->isReferenceType()) {
|
|
|
|
QualType EltTy = Result->isPointerType() ?
|
|
|
|
Result->getAsPointerType()->getPointeeType() :
|
|
|
|
Result->getAsReferenceType()->getPointeeType();
|
2008-04-02 21:35:06 +04:00
|
|
|
|
2009-03-24 23:32:41 +03:00
|
|
|
// If we have a pointer or reference, the pointee must have an object
|
2008-04-02 21:35:06 +04:00
|
|
|
// incomplete type.
|
|
|
|
if (!EltTy->isIncompleteOrObjectType()) {
|
|
|
|
Diag(DS.getRestrictSpecLoc(),
|
2008-11-20 09:06:08 +03:00
|
|
|
diag::err_typecheck_invalid_restrict_invalid_pointee)
|
2008-11-24 09:25:27 +03:00
|
|
|
<< EltTy << DS.getSourceRange();
|
2008-04-02 21:35:06 +04:00
|
|
|
TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier.
|
|
|
|
}
|
|
|
|
} else {
|
2008-04-02 10:50:17 +04:00
|
|
|
Diag(DS.getRestrictSpecLoc(),
|
2008-11-20 09:06:08 +03:00
|
|
|
diag::err_typecheck_invalid_restrict_not_pointer)
|
2008-11-24 09:25:27 +03:00
|
|
|
<< Result << DS.getSourceRange();
|
2008-04-02 21:35:06 +04:00
|
|
|
TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier.
|
2008-04-02 10:50:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification
|
|
|
|
// of a function type includes any type qualifiers, the behavior is
|
|
|
|
// undefined."
|
|
|
|
if (Result->isFunctionType() && TypeQuals) {
|
|
|
|
// Get some location to point at, either the C or V location.
|
|
|
|
SourceLocation Loc;
|
|
|
|
if (TypeQuals & QualType::Const)
|
|
|
|
Loc = DS.getConstSpecLoc();
|
|
|
|
else {
|
|
|
|
assert((TypeQuals & QualType::Volatile) &&
|
|
|
|
"Has CV quals but not C or V?");
|
|
|
|
Loc = DS.getVolatileSpecLoc();
|
|
|
|
}
|
2008-11-20 09:06:08 +03:00
|
|
|
Diag(Loc, diag::warn_typecheck_function_qualifiers)
|
2008-11-24 09:25:27 +03:00
|
|
|
<< Result << DS.getSourceRange();
|
2008-04-02 10:50:17 +04:00
|
|
|
}
|
|
|
|
|
2008-11-03 18:51:28 +03:00
|
|
|
// 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.
|
2009-02-09 18:09:02 +03:00
|
|
|
// FIXME: Shouldn't we be checking SCS_typedef here?
|
|
|
|
if (DS.getTypeSpecType() == DeclSpec::TST_typename &&
|
2008-11-03 18:51:28 +03:00
|
|
|
TypeQuals && Result->isReferenceType()) {
|
|
|
|
TypeQuals &= ~QualType::Const;
|
|
|
|
TypeQuals &= ~QualType::Volatile;
|
|
|
|
}
|
|
|
|
|
2008-04-02 10:50:17 +04:00
|
|
|
Result = Result.getQualifiedType(TypeQuals);
|
|
|
|
}
|
2008-02-21 04:07:18 +03:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2009-02-28 03:25:32 +03:00
|
|
|
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.
|
2009-03-17 02:22:08 +03:00
|
|
|
QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
|
2009-02-28 03:25:32 +03:00
|
|
|
SourceLocation Loc, DeclarationName Entity) {
|
2009-03-17 02:22:08 +03:00
|
|
|
if (LValueRef) {
|
|
|
|
if (const RValueReferenceType *R = T->getAsRValueReferenceType()) {
|
2009-03-23 00:28:55 +03:00
|
|
|
// C++0x [dcl.typedef]p9: If a typedef TD names a type that is a
|
|
|
|
// reference to a type T, and attempt to create the type "lvalue
|
|
|
|
// reference to cv TD" creates the type "lvalue reference to T".
|
|
|
|
// We use the qualifiers (restrict or none) of the original reference,
|
|
|
|
// not the new ones. This is consistent with GCC.
|
2009-03-17 02:22:08 +03:00
|
|
|
return Context.getLValueReferenceType(R->getPointeeType()).
|
2009-03-23 00:28:55 +03:00
|
|
|
getQualifiedType(T.getCVRQualifiers());
|
2009-03-17 02:22:08 +03:00
|
|
|
}
|
|
|
|
}
|
2009-02-28 03:25:32 +03:00
|
|
|
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.
|
2009-03-17 02:22:08 +03:00
|
|
|
if (LValueRef)
|
|
|
|
return Context.getLValueReferenceType(T).getQualifiedType(Quals);
|
|
|
|
return Context.getRValueReferenceType(T).getQualifiedType(Quals);
|
2009-02-28 03:25:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \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]())
|
2009-03-09 19:13:40 +03:00
|
|
|
if (RequireCompleteType(Loc, T,
|
2009-02-28 03:25:32 +03:00
|
|
|
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()) {
|
2009-04-27 05:55:56 +04:00
|
|
|
Diag(Loc, diag::err_objc_array_of_interfaces) << T;
|
|
|
|
return QualType();
|
2009-02-28 03:25:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2009-04-27 01:57:51 +04:00
|
|
|
if (ASM == ArrayType::Star)
|
|
|
|
T = Context.getVariableArrayType(T, 0, ASM, Quals);
|
|
|
|
else
|
|
|
|
T = Context.getIncompleteArrayType(T, ASM, Quals);
|
2009-02-28 03:25:32 +03:00
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
2009-02-28 04:04:19 +03:00
|
|
|
/// \brief Build a function type.
|
|
|
|
///
|
|
|
|
/// This routine checks the function type according to C++ rules and
|
|
|
|
/// under the assumption that the result type and parameter types have
|
|
|
|
/// just been instantiated from a template. It therefore duplicates
|
2009-03-03 07:44:36 +03:00
|
|
|
/// some of the behavior of GetTypeForDeclarator, but in a much
|
2009-02-28 04:04:19 +03:00
|
|
|
/// simpler form that is only suitable for this narrow use case.
|
|
|
|
///
|
|
|
|
/// \param T The return type of the function.
|
|
|
|
///
|
|
|
|
/// \param ParamTypes The parameter types of the function. This array
|
|
|
|
/// will be modified to account for adjustments to the types of the
|
|
|
|
/// function parameters.
|
|
|
|
///
|
|
|
|
/// \param NumParamTypes The number of parameter types in ParamTypes.
|
|
|
|
///
|
|
|
|
/// \param Variadic Whether this is a variadic function type.
|
|
|
|
///
|
|
|
|
/// \param Quals The cvr-qualifiers to be applied to the function type.
|
|
|
|
///
|
|
|
|
/// \param Loc The location of the entity whose type involves this
|
|
|
|
/// function type or, if there is no such entity, the location of the
|
|
|
|
/// type that will have function type.
|
|
|
|
///
|
|
|
|
/// \param Entity The name of the entity that involves the function
|
|
|
|
/// type, if known.
|
|
|
|
///
|
|
|
|
/// \returns A suitable function type, if there are no
|
|
|
|
/// errors. Otherwise, returns a NULL type.
|
|
|
|
QualType Sema::BuildFunctionType(QualType T,
|
|
|
|
QualType *ParamTypes,
|
|
|
|
unsigned NumParamTypes,
|
|
|
|
bool Variadic, unsigned Quals,
|
|
|
|
SourceLocation Loc, DeclarationName Entity) {
|
|
|
|
if (T->isArrayType() || T->isFunctionType()) {
|
|
|
|
Diag(Loc, diag::err_func_returning_array_function) << T;
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Invalid = false;
|
|
|
|
for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
|
2009-03-24 02:06:20 +03:00
|
|
|
QualType ParamType = adjustParameterType(ParamTypes[Idx]);
|
|
|
|
if (ParamType->isVoidType()) {
|
2009-02-28 04:04:19 +03:00
|
|
|
Diag(Loc, diag::err_param_with_void_type);
|
|
|
|
Invalid = true;
|
|
|
|
}
|
2009-02-28 03:25:32 +03:00
|
|
|
|
2009-02-28 04:04:19 +03:00
|
|
|
ParamTypes[Idx] = ParamType;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Invalid)
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
|
|
|
|
Quals);
|
|
|
|
}
|
|
|
|
|
2009-02-05 01:31:32 +03:00
|
|
|
/// GetTypeForDeclarator - Convert the type for the specified
|
|
|
|
/// declarator to Type instances. Skip the outermost Skip type
|
|
|
|
/// objects.
|
2008-12-02 17:43:59 +03:00
|
|
|
QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
|
2009-02-05 01:31:32 +03:00
|
|
|
bool OmittedReturnType = false;
|
|
|
|
|
|
|
|
if (D.getContext() == Declarator::BlockLiteralContext
|
|
|
|
&& Skip == 0
|
|
|
|
&& !D.getDeclSpec().hasTypeSpecifier()
|
|
|
|
&& (D.getNumTypeObjects() == 0
|
|
|
|
|| (D.getNumTypeObjects() == 1
|
|
|
|
&& D.getTypeObject(0).Kind == DeclaratorChunk::Function)))
|
|
|
|
OmittedReturnType = true;
|
|
|
|
|
2007-08-28 20:40:32 +04:00
|
|
|
// long long is a C99 feature.
|
2007-08-28 20:41:29 +04:00
|
|
|
if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
|
2007-08-28 20:40:32 +04:00
|
|
|
D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
|
|
|
|
Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong);
|
2009-01-31 01:09:00 +03:00
|
|
|
|
|
|
|
// Determine the type of the declarator. Not all forms of declarator
|
|
|
|
// have a type.
|
|
|
|
QualType T;
|
|
|
|
switch (D.getKind()) {
|
|
|
|
case Declarator::DK_Abstract:
|
|
|
|
case Declarator::DK_Normal:
|
2009-02-05 01:31:32 +03:00
|
|
|
case Declarator::DK_Operator: {
|
2009-04-22 09:27:59 +04:00
|
|
|
const DeclSpec &DS = D.getDeclSpec();
|
|
|
|
if (OmittedReturnType) {
|
2009-02-05 01:31:32 +03:00
|
|
|
// We default to a dependent type initially. Can be modified by
|
|
|
|
// the first return statement.
|
|
|
|
T = Context.DependentTy;
|
2009-04-22 09:27:59 +04:00
|
|
|
} else {
|
2009-04-25 12:06:05 +04:00
|
|
|
bool isInvalid = false;
|
|
|
|
T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid);
|
|
|
|
if (isInvalid)
|
|
|
|
D.setInvalidType(true);
|
2009-02-18 20:45:20 +03:00
|
|
|
}
|
2009-01-31 01:09:00 +03:00
|
|
|
break;
|
2009-02-05 01:31:32 +03:00
|
|
|
}
|
2009-01-31 01:09:00 +03:00
|
|
|
|
|
|
|
case Declarator::DK_Constructor:
|
|
|
|
case Declarator::DK_Destructor:
|
|
|
|
case Declarator::DK_Conversion:
|
|
|
|
// Constructors and destructors don't have return types. Use
|
|
|
|
// "void" instead. Conversion operators will check their return
|
|
|
|
// types separately.
|
|
|
|
T = Context.VoidTy;
|
|
|
|
break;
|
|
|
|
}
|
2008-11-21 22:14:01 +03:00
|
|
|
|
2009-02-28 03:25:32 +03:00
|
|
|
// The name we're declaring, if any.
|
|
|
|
DeclarationName Name;
|
|
|
|
if (D.getIdentifier())
|
|
|
|
Name = D.getIdentifier();
|
|
|
|
|
2009-02-05 01:31:32 +03:00
|
|
|
// Walk the DeclTypeInfo, building the recursive type as we go.
|
|
|
|
// DeclTypeInfos are ordered from the identifier out, which is
|
|
|
|
// opposite of what we want :).
|
2008-12-02 17:43:59 +03:00
|
|
|
for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) {
|
|
|
|
DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip);
|
2007-07-11 21:01:13 +04:00
|
|
|
switch (DeclType.Kind) {
|
|
|
|
default: assert(0 && "Unknown decltype!");
|
2008-08-27 20:04:49 +04:00
|
|
|
case DeclaratorChunk::BlockPointer:
|
2009-03-27 07:18:06 +03:00
|
|
|
// If blocks are disabled, emit an error.
|
|
|
|
if (!LangOpts.Blocks)
|
|
|
|
Diag(DeclType.Loc, diag::err_blocks_disable);
|
|
|
|
|
2008-08-27 20:04:49 +04:00
|
|
|
if (!T.getTypePtr()->isFunctionType())
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_nonfunction_block_type);
|
|
|
|
else
|
2009-05-08 01:56:17 +04:00
|
|
|
T = (Context.getBlockPointerType(T)
|
|
|
|
.getQualifiedType(DeclType.Cls.TypeQuals));
|
2008-08-27 20:04:49 +04:00
|
|
|
break;
|
2007-07-11 21:01:13 +04:00
|
|
|
case DeclaratorChunk::Pointer:
|
2009-02-28 03:25:32 +03:00
|
|
|
T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
2009-02-28 03:25:32 +03:00
|
|
|
case DeclaratorChunk::Reference:
|
2009-03-17 02:22:08 +03:00
|
|
|
T = BuildReferenceType(T, DeclType.Ref.LValueRef,
|
|
|
|
DeclType.Ref.HasRestrict ? QualType::Restrict : 0,
|
2009-02-28 03:25:32 +03:00
|
|
|
DeclType.Loc, Name);
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
|
|
|
case DeclaratorChunk::Array: {
|
2008-04-02 05:05:10 +04:00
|
|
|
DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
|
2007-08-28 20:54:00 +04:00
|
|
|
Expr *ArraySize = static_cast<Expr*>(ATI.NumElts);
|
2007-07-11 21:01:13 +04:00
|
|
|
ArrayType::ArraySizeModifier ASM;
|
|
|
|
if (ATI.isStar)
|
|
|
|
ASM = ArrayType::Star;
|
|
|
|
else if (ATI.hasStatic)
|
|
|
|
ASM = ArrayType::Static;
|
|
|
|
else
|
|
|
|
ASM = ArrayType::Normal;
|
2009-04-27 01:57:51 +04:00
|
|
|
if (ASM == ArrayType::Star &&
|
|
|
|
D.getContext() != Declarator::PrototypeContext) {
|
|
|
|
// FIXME: This check isn't quite right: it allows star in prototypes
|
|
|
|
// for function definitions, and disallows some edge cases detailed
|
|
|
|
// in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html
|
|
|
|
Diag(DeclType.Loc, diag::err_array_star_outside_prototype);
|
|
|
|
ASM = ArrayType::Normal;
|
|
|
|
D.setInvalidType(true);
|
|
|
|
}
|
2009-02-28 03:25:32 +03:00
|
|
|
T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name);
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
|
|
|
}
|
2009-01-25 00:16:55 +03:00
|
|
|
case DeclaratorChunk::Function: {
|
2007-07-11 21:01:13 +04:00
|
|
|
// If the function declarator has a prototype (i.e. it is not () and
|
|
|
|
// does not have a K&R-style identifier list), then the arguments are part
|
|
|
|
// of the type, otherwise the argument list is ().
|
|
|
|
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
|
2007-12-19 21:01:43 +03:00
|
|
|
|
2007-12-19 08:31:29 +03:00
|
|
|
// C99 6.7.5.3p1: The return type may not be a function or array type.
|
2007-12-19 21:01:43 +03:00
|
|
|
if (T->isArrayType() || T->isFunctionType()) {
|
2008-11-24 09:25:27 +03:00
|
|
|
Diag(DeclType.Loc, diag::err_func_returning_array_function) << T;
|
2007-12-19 08:31:29 +03:00
|
|
|
T = Context.IntTy;
|
|
|
|
D.setInvalidType(true);
|
|
|
|
}
|
|
|
|
|
2008-08-26 01:31:01 +04:00
|
|
|
if (FTI.NumArgs == 0) {
|
2008-10-16 21:31:08 +04:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
// C++ 8.3.5p2: If the parameter-declaration-clause is empty, the
|
|
|
|
// function takes no arguments.
|
2008-10-25 01:46:40 +04:00
|
|
|
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals);
|
2009-02-18 10:07:28 +03:00
|
|
|
} 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);
|
2008-10-16 21:31:08 +04:00
|
|
|
} else {
|
|
|
|
// Simple void foo(), where the incoming T is the result type.
|
2009-02-27 02:50:07 +03:00
|
|
|
T = Context.getFunctionNoProtoType(T);
|
2008-10-16 21:31:08 +04:00
|
|
|
}
|
2008-08-26 01:31:01 +04:00
|
|
|
} else if (FTI.ArgInfo[0].Param == 0) {
|
2007-07-11 21:01:13 +04:00
|
|
|
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition.
|
2008-08-26 01:31:01 +04:00
|
|
|
Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
|
2007-07-11 21:01:13 +04:00
|
|
|
} else {
|
|
|
|
// Otherwise, we have a function with an argument list that is
|
|
|
|
// potentially variadic.
|
|
|
|
llvm::SmallVector<QualType, 16> ArgTys;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
|
2009-03-28 22:18:32 +03:00
|
|
|
ParmVarDecl *Param =
|
|
|
|
cast<ParmVarDecl>(FTI.ArgInfo[i].Param.getAs<Decl>());
|
2008-04-10 06:22:51 +04:00
|
|
|
QualType ArgTy = Param->getType();
|
2007-07-21 09:30:18 +04:00
|
|
|
assert(!ArgTy.isNull() && "Couldn't parse type?");
|
2009-03-24 02:06:20 +03:00
|
|
|
|
|
|
|
// Adjust the parameter type.
|
2009-03-24 02:17:00 +03:00
|
|
|
assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?");
|
2009-03-24 02:06:20 +03:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// Look for 'void'. void is allowed only as a single argument to a
|
|
|
|
// function with no other parameters (C99 6.7.5.3p10). We record
|
2009-02-27 02:50:07 +03:00
|
|
|
// int(void) as a FunctionProtoType with an empty argument list.
|
2009-03-24 02:06:20 +03:00
|
|
|
if (ArgTy->isVoidType()) {
|
2007-07-11 21:01:13 +04:00
|
|
|
// If this is something like 'float(int, void)', reject it. 'void'
|
|
|
|
// is an incomplete type (C99 6.2.5p19) and function decls cannot
|
|
|
|
// have arguments of incomplete type.
|
|
|
|
if (FTI.NumArgs != 1 || FTI.isVariadic) {
|
|
|
|
Diag(DeclType.Loc, diag::err_void_only_param);
|
2007-07-21 09:18:12 +04:00
|
|
|
ArgTy = Context.IntTy;
|
2008-04-10 06:22:51 +04:00
|
|
|
Param->setType(ArgTy);
|
2007-07-21 09:18:12 +04:00
|
|
|
} else if (FTI.ArgInfo[i].Ident) {
|
|
|
|
// Reject, but continue to parse 'int(void abc)'.
|
2007-07-11 21:01:13 +04:00
|
|
|
Diag(FTI.ArgInfo[i].IdentLoc,
|
2007-07-21 09:26:43 +04:00
|
|
|
diag::err_param_with_void_type);
|
2007-07-21 09:18:12 +04:00
|
|
|
ArgTy = Context.IntTy;
|
2008-04-10 06:22:51 +04:00
|
|
|
Param->setType(ArgTy);
|
2007-07-21 09:18:12 +04:00
|
|
|
} else {
|
|
|
|
// Reject, but continue to parse 'float(const void)'.
|
2008-02-20 23:55:12 +03:00
|
|
|
if (ArgTy.getCVRQualifiers())
|
2007-07-21 09:18:12 +04:00
|
|
|
Diag(DeclType.Loc, diag::err_void_param_qualified);
|
|
|
|
|
|
|
|
// Do not add 'void' to the ArgTys list.
|
|
|
|
break;
|
|
|
|
}
|
2008-08-26 01:31:01 +04:00
|
|
|
} else if (!FTI.hasPrototype) {
|
|
|
|
if (ArgTy->isPromotableIntegerType()) {
|
|
|
|
ArgTy = Context.IntTy;
|
|
|
|
} else if (const BuiltinType* BTy = ArgTy->getAsBuiltinType()) {
|
|
|
|
if (BTy->getKind() == BuiltinType::Float)
|
|
|
|
ArgTy = Context.DoubleTy;
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ArgTys.push_back(ArgTy);
|
|
|
|
}
|
|
|
|
T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
|
2008-10-25 01:46:40 +04:00
|
|
|
FTI.isVariadic, FTI.TypeQuals);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-01-25 00:16:55 +03:00
|
|
|
case DeclaratorChunk::MemberPointer:
|
|
|
|
// The scope spec must refer to a class, or be dependent.
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67265 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-19 03:18:19 +03:00
|
|
|
DeclContext *DC = computeDeclContext(DeclType.Mem.Scope());
|
2009-01-25 00:16:55 +03:00
|
|
|
QualType ClsType;
|
|
|
|
// FIXME: Extend for dependent types when it's actually supported.
|
|
|
|
// See ActOnCXXNestedNameSpecifier.
|
|
|
|
if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) {
|
|
|
|
ClsType = Context.getTagDeclType(RD);
|
|
|
|
} else {
|
|
|
|
if (DC) {
|
|
|
|
Diag(DeclType.Mem.Scope().getBeginLoc(),
|
|
|
|
diag::err_illegal_decl_mempointer_in_nonclass)
|
|
|
|
<< (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
|
|
|
|
<< DeclType.Mem.Scope().getRange();
|
|
|
|
}
|
|
|
|
D.setInvalidType(true);
|
|
|
|
ClsType = Context.IntTy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ 8.3.3p3: A pointer to member shall not pointer to ... a member
|
|
|
|
// with reference type, or "cv void."
|
|
|
|
if (T->isReferenceType()) {
|
|
|
|
Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference)
|
|
|
|
<< (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
|
|
|
|
D.setInvalidType(true);
|
|
|
|
T = Context.IntTy;
|
|
|
|
}
|
|
|
|
if (T->isVoidType()) {
|
|
|
|
Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void)
|
|
|
|
<< (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
|
|
|
|
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.Mem.TypeQuals & QualType::Restrict) &&
|
|
|
|
!T->isIncompleteOrObjectType()) {
|
|
|
|
Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
|
|
|
|
<< T;
|
|
|
|
DeclType.Mem.TypeQuals &= ~QualType::Restrict;
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:43:20 +03:00
|
|
|
T = Context.getMemberPointerType(T, ClsType.getTypePtr()).
|
|
|
|
getQualifiedType(DeclType.Mem.TypeQuals);
|
2009-01-25 00:16:55 +03:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-02-28 03:25:32 +03:00
|
|
|
if (T.isNull()) {
|
|
|
|
D.setInvalidType(true);
|
|
|
|
T = Context.IntTy;
|
|
|
|
}
|
|
|
|
|
2008-06-29 04:50:08 +04:00
|
|
|
// See if there are any attributes on this declarator chunk.
|
|
|
|
if (const AttributeList *AL = DeclType.getAttrs())
|
|
|
|
ProcessTypeAttributeList(T, AL);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-10-25 01:46:40 +04:00
|
|
|
|
|
|
|
if (getLangOptions().CPlusPlus && T->isFunctionType()) {
|
2009-02-27 02:50:07 +03:00
|
|
|
const FunctionProtoType *FnTy = T->getAsFunctionProtoType();
|
|
|
|
assert(FnTy && "Why oh why is there not a FunctionProtoType here ?");
|
2008-10-25 01:46:40 +04:00
|
|
|
|
|
|
|
// C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type
|
|
|
|
// 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.
|
|
|
|
if (FnTy->getTypeQuals() != 0 &&
|
|
|
|
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
|
2008-12-16 02:53:10 +03:00
|
|
|
((D.getContext() != Declarator::MemberContext &&
|
|
|
|
(!D.getCXXScopeSpec().isSet() ||
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67265 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-19 03:18:19 +03:00
|
|
|
!computeDeclContext(D.getCXXScopeSpec())->isRecord())) ||
|
2008-10-25 01:46:40 +04:00
|
|
|
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
|
|
|
|
if (D.isFunctionDeclarator())
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
|
|
|
|
else
|
|
|
|
Diag(D.getIdentifierLoc(),
|
|
|
|
diag::err_invalid_qualified_typedef_function_type_use);
|
|
|
|
|
|
|
|
// Strip the cv-quals from the type.
|
|
|
|
T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
|
2008-10-26 19:43:14 +03:00
|
|
|
FnTy->getNumArgs(), FnTy->isVariadic(), 0);
|
2008-10-25 01:46:40 +04:00
|
|
|
}
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2008-06-29 04:19:33 +04:00
|
|
|
// If there were any type attributes applied to the decl itself (not the
|
|
|
|
// type, apply the type attribute to the type!)
|
|
|
|
if (const AttributeList *Attrs = D.getAttributes())
|
2008-06-29 04:50:08 +04:00
|
|
|
ProcessTypeAttributeList(T, Attrs);
|
2008-06-29 04:19:33 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
2008-01-07 22:49:32 +03:00
|
|
|
/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
|
2007-11-10 01:27:59 +03:00
|
|
|
/// declarator
|
2009-03-28 22:18:32 +03:00
|
|
|
QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
|
|
|
|
ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>());
|
2007-11-09 02:49:49 +03:00
|
|
|
QualType T = MDecl->getResultType();
|
|
|
|
llvm::SmallVector<QualType, 16> ArgTys;
|
|
|
|
|
2007-11-09 20:18:29 +03:00
|
|
|
// Add the first two invisible argument types for self and _cmd.
|
2009-01-09 20:18:27 +03:00
|
|
|
if (MDecl->isInstanceMethod()) {
|
2008-01-07 22:49:32 +03:00
|
|
|
QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface());
|
2007-11-09 22:52:12 +03:00
|
|
|
selfTy = Context.getPointerType(selfTy);
|
|
|
|
ArgTys.push_back(selfTy);
|
2009-02-20 21:43:26 +03:00
|
|
|
} else
|
2008-01-07 22:49:32 +03:00
|
|
|
ArgTys.push_back(Context.getObjCIdType());
|
|
|
|
ArgTys.push_back(Context.getObjCSelType());
|
2007-11-09 20:18:29 +03:00
|
|
|
|
2009-02-20 21:43:26 +03:00
|
|
|
for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
|
|
|
|
E = MDecl->param_end(); PI != E; ++PI) {
|
|
|
|
QualType ArgTy = (*PI)->getType();
|
2007-11-09 02:49:49 +03:00
|
|
|
assert(!ArgTy.isNull() && "Couldn't parse type?");
|
2009-03-24 02:17:00 +03:00
|
|
|
ArgTy = adjustParameterType(ArgTy);
|
2007-11-09 02:49:49 +03:00
|
|
|
ArgTys.push_back(ArgTy);
|
|
|
|
}
|
|
|
|
T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
|
2008-10-26 19:43:14 +03:00
|
|
|
MDecl->isVariadic(), 0);
|
2007-11-09 02:49:49 +03:00
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
2009-01-26 22:54:48 +03:00
|
|
|
/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that
|
|
|
|
/// may be similar (C++ 4.4), replaces T1 and T2 with the type that
|
|
|
|
/// they point to and return true. If T1 and T2 aren't pointer types
|
|
|
|
/// or pointer-to-member types, or if they are not similar at this
|
|
|
|
/// level, returns false and leaves T1 and T2 unchanged. Top-level
|
|
|
|
/// qualifiers on T1 and T2 are ignored. This function will typically
|
|
|
|
/// be called in a loop that successively "unwraps" pointer and
|
|
|
|
/// pointer-to-member types to compare them at each level.
|
2009-02-17 00:43:00 +03:00
|
|
|
bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) {
|
2008-10-22 18:17:15 +04:00
|
|
|
const PointerType *T1PtrType = T1->getAsPointerType(),
|
|
|
|
*T2PtrType = T2->getAsPointerType();
|
|
|
|
if (T1PtrType && T2PtrType) {
|
|
|
|
T1 = T1PtrType->getPointeeType();
|
|
|
|
T2 = T2PtrType->getPointeeType();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:43:20 +03:00
|
|
|
const MemberPointerType *T1MPType = T1->getAsMemberPointerType(),
|
|
|
|
*T2MPType = T2->getAsMemberPointerType();
|
2009-01-28 21:33:18 +03:00
|
|
|
if (T1MPType && T2MPType &&
|
|
|
|
Context.getCanonicalType(T1MPType->getClass()) ==
|
|
|
|
Context.getCanonicalType(T2MPType->getClass())) {
|
2009-01-25 22:43:20 +03:00
|
|
|
T1 = T1MPType->getPointeeType();
|
|
|
|
T2 = T2MPType->getPointeeType();
|
|
|
|
return true;
|
|
|
|
}
|
2008-10-22 18:17:15 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-12-02 17:43:59 +03:00
|
|
|
Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
|
2007-07-11 21:01:13 +04:00
|
|
|
// C99 6.7.6: Type names have no identifier. This is already validated by
|
|
|
|
// the parser.
|
|
|
|
assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
|
|
|
|
|
2008-12-02 17:43:59 +03:00
|
|
|
QualType T = GetTypeForDeclarator(D, S);
|
2009-04-25 12:47:54 +04:00
|
|
|
if (D.isInvalidType())
|
2009-02-18 20:45:20 +03:00
|
|
|
return true;
|
2007-08-29 00:14:24 +04:00
|
|
|
|
2008-05-07 08:49:29 +04:00
|
|
|
// Check that there are no default arguments (C++ only).
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
CheckExtraCXXDefaultArguments(D);
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
return T.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
|
2008-06-29 04:50:08 +04:00
|
|
|
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type Attribute Processing
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-02-21 04:08:11 +03:00
|
|
|
|
|
|
|
/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the
|
2008-06-29 04:50:08 +04:00
|
|
|
/// specified type. The attribute contains 1 argument, the id of the address
|
|
|
|
/// space for the type.
|
|
|
|
static void HandleAddressSpaceTypeAttribute(QualType &Type,
|
|
|
|
const AttributeList &Attr, Sema &S){
|
2008-02-21 04:08:11 +03:00
|
|
|
// If this type is already address space qualified, reject it.
|
|
|
|
// Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers
|
|
|
|
// for two or more different address spaces."
|
|
|
|
if (Type.getAddressSpace()) {
|
2008-06-29 04:50:08 +04:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
|
|
|
|
return;
|
2008-02-21 04:08:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check the attribute arguments.
|
2008-06-29 03:36:30 +04:00
|
|
|
if (Attr.getNumArgs() != 1) {
|
2008-11-20 09:38:18 +03:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
2008-06-29 04:50:08 +04:00
|
|
|
return;
|
2008-02-21 04:08:11 +03:00
|
|
|
}
|
2008-06-29 03:36:30 +04:00
|
|
|
Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0));
|
2008-02-21 04:08:11 +03:00
|
|
|
llvm::APSInt addrSpace(32);
|
2008-06-29 04:50:08 +04:00
|
|
|
if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
|
2008-11-19 08:27:50 +03:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int)
|
|
|
|
<< ASArgExpr->getSourceRange();
|
2008-06-29 04:50:08 +04:00
|
|
|
return;
|
2008-02-21 04:08:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
|
2009-02-17 21:27:45 +03:00
|
|
|
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
|
2008-06-29 04:50:08 +04:00
|
|
|
}
|
|
|
|
|
2009-02-18 08:09:49 +03:00
|
|
|
/// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the
|
|
|
|
/// specified type. The attribute contains 1 argument, weak or strong.
|
|
|
|
static void HandleObjCGCTypeAttribute(QualType &Type,
|
2009-02-19 01:58:38 +03:00
|
|
|
const AttributeList &Attr, Sema &S) {
|
2009-02-18 08:09:49 +03:00
|
|
|
if (Type.getObjCGCAttr() != QualType::GCNone) {
|
2009-02-18 21:52:41 +03:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc);
|
2009-02-18 08:09:49 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the attribute arguments.
|
2009-02-18 20:52:36 +03:00
|
|
|
if (!Attr.getParameterName()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
|
|
|
|
<< "objc_gc" << 1;
|
|
|
|
return;
|
|
|
|
}
|
2009-02-19 01:58:38 +03:00
|
|
|
QualType::GCAttrTypes GCAttr;
|
2009-02-18 20:52:36 +03:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2009-02-18 08:09:49 +03:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Attr.getParameterName()->isStr("weak"))
|
2009-02-19 01:58:38 +03:00
|
|
|
GCAttr = QualType::Weak;
|
2009-02-18 08:09:49 +03:00
|
|
|
else if (Attr.getParameterName()->isStr("strong"))
|
2009-02-19 01:58:38 +03:00
|
|
|
GCAttr = QualType::Strong;
|
2009-02-18 08:09:49 +03:00
|
|
|
else {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
|
|
|
|
<< "objc_gc" << Attr.getParameterName();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-19 01:58:38 +03:00
|
|
|
Type = S.Context.getObjCGCQualType(Type, GCAttr);
|
2009-02-18 08:09:49 +03:00
|
|
|
}
|
|
|
|
|
2008-06-29 04:50:08 +04:00
|
|
|
void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
|
|
|
|
// Scan through and apply attributes to this type where it makes sense. Some
|
|
|
|
// attributes (such as __address_space__, __vector_size__, etc) apply to the
|
|
|
|
// type, but others can be present in the type specifiers even though they
|
|
|
|
// apply to the decl. Here we apply type attributes and ignore the rest.
|
|
|
|
for (; AL; AL = AL->getNext()) {
|
|
|
|
// If this is an attribute we can handle, do so now, otherwise, add it to
|
|
|
|
// the LeftOverAttrs list for rechaining.
|
|
|
|
switch (AL->getKind()) {
|
|
|
|
default: break;
|
|
|
|
case AttributeList::AT_address_space:
|
|
|
|
HandleAddressSpaceTypeAttribute(Result, *AL, *this);
|
|
|
|
break;
|
2009-02-18 08:09:49 +03:00
|
|
|
case AttributeList::AT_objc_gc:
|
|
|
|
HandleObjCGCTypeAttribute(Result, *AL, *this);
|
|
|
|
break;
|
2008-06-29 04:50:08 +04:00
|
|
|
}
|
|
|
|
}
|
2008-02-21 04:08:11 +03:00
|
|
|
}
|
|
|
|
|
2009-03-09 19:13:40 +03:00
|
|
|
/// @brief Ensure that the type T is a complete type.
|
2009-01-19 22:26:10 +03:00
|
|
|
///
|
|
|
|
/// This routine checks whether the type @p T is complete in any
|
|
|
|
/// context where a complete type is required. If @p T is a complete
|
2009-03-09 19:13:40 +03:00
|
|
|
/// type, returns false. If @p T is a class template specialization,
|
|
|
|
/// this routine then attempts to perform class template
|
|
|
|
/// instantiation. If instantiation fails, or if @p T is incomplete
|
|
|
|
/// and cannot be completed, issues the diagnostic @p diag (giving it
|
|
|
|
/// the type @p T) and returns true.
|
2009-01-19 22:26:10 +03:00
|
|
|
///
|
|
|
|
/// @param Loc The location in the source that the incomplete type
|
|
|
|
/// diagnostic should refer to.
|
|
|
|
///
|
|
|
|
/// @param T The type that this routine is examining for completeness.
|
|
|
|
///
|
|
|
|
/// @param diag The diagnostic value (e.g.,
|
|
|
|
/// @c diag::err_typecheck_decl_incomplete_type) that will be used
|
|
|
|
/// for the error message if @p T is incomplete.
|
|
|
|
///
|
|
|
|
/// @param Range1 An optional range in the source code that will be a
|
|
|
|
/// part of the "incomplete type" error message.
|
|
|
|
///
|
|
|
|
/// @param Range2 An optional range in the source code that will be a
|
|
|
|
/// part of the "incomplete type" error message.
|
|
|
|
///
|
|
|
|
/// @param PrintType If non-NULL, the type that should be printed
|
|
|
|
/// instead of @p T. This parameter should be used when the type that
|
|
|
|
/// we're checking for incompleteness isn't the type that should be
|
|
|
|
/// displayed to the user, e.g., when T is a type and PrintType is a
|
|
|
|
/// pointer to T.
|
|
|
|
///
|
|
|
|
/// @returns @c true if @p T is incomplete and a diagnostic was emitted,
|
|
|
|
/// @c false otherwise.
|
2009-03-09 19:13:40 +03:00
|
|
|
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
|
2009-04-24 04:30:45 +04:00
|
|
|
SourceRange Range1, SourceRange Range2,
|
|
|
|
QualType PrintType) {
|
2009-01-19 22:26:10 +03:00
|
|
|
// If we have a complete type, we're done.
|
|
|
|
if (!T->isIncompleteType())
|
|
|
|
return false;
|
|
|
|
|
2009-03-26 00:17:03 +03:00
|
|
|
// If we have a class template specialization or a class member of a
|
|
|
|
// class template specialization, try to instantiate it.
|
|
|
|
if (const RecordType *Record = T->getAsRecordType()) {
|
2009-03-03 07:44:36 +03:00
|
|
|
if (ClassTemplateSpecializationDecl *ClassTemplateSpec
|
2009-03-26 00:17:03 +03:00
|
|
|
= dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
|
2009-03-03 07:44:36 +03:00
|
|
|
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
|
|
|
|
// Update the class template specialization's location to
|
|
|
|
// refer to the point of instantiation.
|
|
|
|
if (Loc.isValid())
|
|
|
|
ClassTemplateSpec->setLocation(Loc);
|
|
|
|
return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
|
|
|
|
/*ExplicitInstantiation=*/false);
|
|
|
|
}
|
2009-03-26 00:17:03 +03:00
|
|
|
} else if (CXXRecordDecl *Rec
|
|
|
|
= dyn_cast<CXXRecordDecl>(Record->getDecl())) {
|
|
|
|
if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
|
|
|
|
// Find the class template specialization that surrounds this
|
|
|
|
// member class.
|
|
|
|
ClassTemplateSpecializationDecl *Spec = 0;
|
|
|
|
for (DeclContext *Parent = Rec->getDeclContext();
|
|
|
|
Parent && !Spec; Parent = Parent->getParent())
|
|
|
|
Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
|
|
|
|
assert(Spec && "Not a member of a class template specialization?");
|
2009-05-13 04:25:59 +04:00
|
|
|
return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(),
|
|
|
|
/*ExplicitInstantiation=*/false);
|
2009-03-26 00:17:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-03-03 07:44:36 +03:00
|
|
|
|
2009-01-19 22:26:10 +03:00
|
|
|
if (PrintType.isNull())
|
|
|
|
PrintType = T;
|
|
|
|
|
|
|
|
// We have an incomplete type. Produce a diagnostic.
|
|
|
|
Diag(Loc, diag) << PrintType << Range1 << Range2;
|
2008-05-27 07:33:27 +04:00
|
|
|
|
2009-01-19 22:26:10 +03:00
|
|
|
// If the type was a forward declaration of a class/struct/union
|
|
|
|
// type, produce
|
|
|
|
const TagType *Tag = 0;
|
|
|
|
if (const RecordType *Record = T->getAsRecordType())
|
|
|
|
Tag = Record;
|
|
|
|
else if (const EnumType *Enum = T->getAsEnumType())
|
|
|
|
Tag = Enum;
|
|
|
|
|
|
|
|
if (Tag && !Tag->getDecl()->isInvalidDecl())
|
|
|
|
Diag(Tag->getDecl()->getLocation(),
|
|
|
|
Tag->isBeingDefined() ? diag::note_type_being_defined
|
|
|
|
: diag::note_forward_declaration)
|
|
|
|
<< QualType(Tag, 0);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2009-03-19 03:39:20 +03:00
|
|
|
|
|
|
|
/// \brief Retrieve a version of the type 'T' that is qualified by the
|
|
|
|
/// nested-name-specifier contained in SS.
|
|
|
|
QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
|
|
|
|
if (!SS.isSet() || SS.isInvalid() || T.isNull())
|
|
|
|
return T;
|
|
|
|
|
2009-03-27 02:50:42 +03:00
|
|
|
NestedNameSpecifier *NNS
|
2009-03-27 02:56:24 +03:00
|
|
|
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
|
2009-03-27 02:50:42 +03:00
|
|
|
return Context.getQualifiedNameType(NNS, T);
|
2009-03-19 03:39:20 +03:00
|
|
|
}
|