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()) {
|
2009-06-29 20:22:52 +04:00
|
|
|
Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
|
|
|
|
DS.getNumProtocolQualifiers());
|
2008-07-26 04:46:50 +04:00
|
|
|
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();
|
2009-06-03 16:22:01 +04:00
|
|
|
Diag(DeclLoc, diag::ext_missing_declspec)
|
2009-04-22 09:27:59 +04:00
|
|
|
<< 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();
|
|
|
|
|
2009-06-26 08:45:06 +04:00
|
|
|
if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft) {
|
2009-04-22 09:27:59 +04:00
|
|
|
Diag(DeclLoc, diag::err_missing_type_specifier)
|
|
|
|
<< DS.getSourceRange();
|
2009-06-26 08:45:06 +04:00
|
|
|
|
|
|
|
// When this occurs in C++ code, often something is very broken with the
|
|
|
|
// value being declared, poison it as invalid so we don't get chains of
|
|
|
|
// errors.
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
2009-06-03 16:22:01 +04:00
|
|
|
Diag(DeclLoc, diag::ext_missing_type_specifier)
|
2009-04-22 09:27:59 +04:00
|
|
|
<< DS.getSourceRange();
|
2009-06-26 08:45:06 +04:00
|
|
|
}
|
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()) {
|
2009-05-16 11:39:55 +04:00
|
|
|
// FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have
|
|
|
|
// this "hack" for now...
|
2009-02-09 18:09:02 +03:00
|
|
|
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>
|
2009-06-29 20:22:52 +04:00
|
|
|
Result = Context.getObjCObjectPointerType(0, (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-06-24 21:47:40 +04:00
|
|
|
case DeclSpec::TST_decltype: {
|
|
|
|
Expr *E = static_cast<Expr *>(DS.getTypeRep());
|
|
|
|
assert(E && "Didn't get an expression for decltype?");
|
|
|
|
// TypeQuals handled by caller.
|
2009-06-30 02:58:55 +04:00
|
|
|
Result = BuildDecltypeType(E);
|
|
|
|
if (Result.isNull()) {
|
|
|
|
Result = Context.IntTy;
|
|
|
|
isInvalid = true;
|
|
|
|
}
|
2009-06-24 21:47:40 +04:00
|
|
|
break;
|
|
|
|
}
|
2009-06-26 22:41:36 +04:00
|
|
|
case DeclSpec::TST_auto: {
|
|
|
|
// TypeQuals handled by caller.
|
|
|
|
Result = Context.UndeducedAutoTy;
|
|
|
|
break;
|
|
|
|
}
|
2009-06-24 21:47:40 +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();
|
|
|
|
}
|
|
|
|
|
2009-06-26 23:33:28 +04:00
|
|
|
if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) {
|
|
|
|
Diag(Loc, diag::err_illegal_decl_array_of_auto)
|
|
|
|
<< getPrintableNameForEntity(Entity);
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
2009-02-28 03:25:32 +03:00
|
|
|
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-06-18 01:51:59 +04:00
|
|
|
|
|
|
|
/// \brief Build an ext-vector type.
|
|
|
|
///
|
|
|
|
/// Run the required checks for the extended vector type.
|
|
|
|
QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
|
|
|
|
SourceLocation AttrLoc) {
|
|
|
|
|
|
|
|
Expr *Arg = (Expr *)ArraySize.get();
|
|
|
|
|
|
|
|
// unlike gcc's vector_size attribute, we do not allow vectors to be defined
|
|
|
|
// in conjunction with complex types (pointers, arrays, functions, etc.).
|
|
|
|
if (!T->isDependentType() &&
|
|
|
|
!T->isIntegerType() && !T->isRealFloatingType()) {
|
|
|
|
Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T;
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
|
|
|
|
llvm::APSInt vecSize(32);
|
|
|
|
if (!Arg->isIntegerConstantExpr(vecSize, Context)) {
|
|
|
|
Diag(AttrLoc, diag::err_attribute_argument_not_int)
|
|
|
|
<< "ext_vector_type" << Arg->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// unlike gcc's vector_size attribute, the size is specified as the
|
|
|
|
// number of elements, not the number of bytes.
|
|
|
|
unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
|
|
|
|
|
|
|
|
if (vectorSize == 0) {
|
|
|
|
Diag(AttrLoc, diag::err_attribute_zero_size)
|
|
|
|
<< Arg->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!T->isDependentType())
|
|
|
|
return Context.getExtVectorType(T, vectorSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Context.getDependentSizedExtVectorType(T, ArraySize.takeAs<Expr>(),
|
|
|
|
AttrLoc);
|
|
|
|
}
|
2009-02-28 03:25:32 +03:00
|
|
|
|
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-06-10 02:17:39 +04:00
|
|
|
|
|
|
|
/// \brief Build a member pointer type \c T Class::*.
|
|
|
|
///
|
|
|
|
/// \param T the type to which the member pointer refers.
|
|
|
|
/// \param Class the class type into which the member pointer points.
|
|
|
|
/// \param Quals Qualifiers applied to the member pointer type
|
|
|
|
/// \param Loc the location where this type begins
|
|
|
|
/// \param Entity the name of the entity that will have this member pointer type
|
|
|
|
///
|
|
|
|
/// \returns a member pointer type, if successful, or a NULL type if there was
|
|
|
|
/// an error.
|
|
|
|
QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
|
|
|
|
unsigned Quals, SourceLocation Loc,
|
|
|
|
DeclarationName Entity) {
|
|
|
|
// Verify that we're not building a pointer to pointer to function with
|
|
|
|
// exception specification.
|
|
|
|
if (CheckDistantExceptionSpec(T)) {
|
|
|
|
Diag(Loc, diag::err_distant_exception_spec);
|
|
|
|
|
|
|
|
// FIXME: If we're doing this as part of template instantiation,
|
|
|
|
// we should return immediately.
|
|
|
|
|
|
|
|
// Build the type anyway, but use the canonical type so that the
|
|
|
|
// exception specifiers are stripped off.
|
|
|
|
T = Context.getCanonicalType(T);
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ 8.3.3p3: A pointer to member shall not pointer to ... a member
|
|
|
|
// with reference type, or "cv void."
|
|
|
|
if (T->isReferenceType()) {
|
2009-06-30 04:06:57 +04:00
|
|
|
Diag(Loc, diag::err_illegal_decl_mempointer_to_reference)
|
2009-06-10 02:17:39 +04:00
|
|
|
<< (Entity? Entity.getAsString() : "type name");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (T->isVoidType()) {
|
|
|
|
Diag(Loc, diag::err_illegal_decl_mempointer_to_void)
|
|
|
|
<< (Entity? Entity.getAsString() : "type name");
|
|
|
|
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;
|
|
|
|
|
|
|
|
// FIXME: If we're doing this as part of template instantiation,
|
|
|
|
// we should return immediately.
|
|
|
|
Quals &= ~QualType::Restrict;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Class->isDependentType() && !Class->isRecordType()) {
|
|
|
|
Diag(Loc, diag::err_mempointer_in_nonclass_type) << Class;
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Context.getMemberPointerType(T, Class.getTypePtr())
|
|
|
|
.getQualifiedType(Quals);
|
|
|
|
}
|
2009-06-13 02:56:54 +04:00
|
|
|
|
|
|
|
/// \brief Build a block pointer type.
|
|
|
|
///
|
|
|
|
/// \param T The type to which we'll be building a block pointer.
|
|
|
|
///
|
|
|
|
/// \param Quals The cvr-qualifiers to be applied to the block pointer type.
|
|
|
|
///
|
|
|
|
/// \param Loc The location of the entity whose type involves this
|
|
|
|
/// block pointer type or, if there is no such entity, the location of the
|
|
|
|
/// type that will have block pointer type.
|
|
|
|
///
|
|
|
|
/// \param Entity The name of the entity that involves the block pointer
|
|
|
|
/// type, if known.
|
|
|
|
///
|
|
|
|
/// \returns A suitable block pointer type, if there are no
|
|
|
|
/// errors. Otherwise, returns a NULL type.
|
|
|
|
QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals,
|
|
|
|
SourceLocation Loc,
|
|
|
|
DeclarationName Entity) {
|
|
|
|
if (!T.getTypePtr()->isFunctionType()) {
|
|
|
|
Diag(Loc, diag::err_nonfunction_block_type);
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Context.getBlockPointerType(T).getQualifiedType(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.
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72555 91177308-0d34-0410-b5e6-96231b3b80d8
2009-05-29 03:31:59 +04:00
|
|
|
///
|
|
|
|
/// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq
|
|
|
|
/// owns the declaration of a type (e.g., the definition of a struct
|
|
|
|
/// type), then *OwnedDecl will receive the owned declaration.
|
|
|
|
QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
|
|
|
|
TagDecl **OwnedDecl) {
|
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);
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72555 91177308-0d34-0410-b5e6-96231b3b80d8
2009-05-29 03:31:59 +04:00
|
|
|
else if (OwnedDecl && DS.isTypeSpecOwned())
|
|
|
|
*OwnedDecl = cast<TagDecl>((Decl *)DS.getTypeRep());
|
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-06-27 02:18:59 +04:00
|
|
|
if (T == Context.UndeducedAutoTy) {
|
|
|
|
int Error = -1;
|
|
|
|
|
|
|
|
switch (D.getContext()) {
|
|
|
|
case Declarator::KNRTypeListContext:
|
|
|
|
assert(0 && "K&R type lists aren't allowed in C++");
|
|
|
|
break;
|
|
|
|
case Declarator::PrototypeContext:
|
|
|
|
Error = 0; // Function prototype
|
|
|
|
break;
|
|
|
|
case Declarator::MemberContext:
|
|
|
|
switch (cast<TagDecl>(CurContext)->getTagKind()) {
|
|
|
|
case TagDecl::TK_enum: assert(0 && "unhandled tag kind"); break;
|
|
|
|
case TagDecl::TK_struct: Error = 1; /* Struct member */ break;
|
|
|
|
case TagDecl::TK_union: Error = 2; /* Union member */ break;
|
|
|
|
case TagDecl::TK_class: Error = 3; /* Class member */ break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Declarator::CXXCatchContext:
|
|
|
|
Error = 4; // Exception declaration
|
|
|
|
break;
|
|
|
|
case Declarator::TemplateParamContext:
|
|
|
|
Error = 5; // Template parameter
|
|
|
|
break;
|
|
|
|
case Declarator::BlockLiteralContext:
|
|
|
|
Error = 6; // Block literal
|
|
|
|
break;
|
|
|
|
case Declarator::FileContext:
|
|
|
|
case Declarator::BlockContext:
|
|
|
|
case Declarator::ForContext:
|
|
|
|
case Declarator::ConditionContext:
|
|
|
|
case Declarator::TypeNameContext:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Error != -1) {
|
|
|
|
Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed)
|
|
|
|
<< Error;
|
|
|
|
T = Context.IntTy;
|
|
|
|
D.setInvalidType(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
2009-06-13 02:56:54 +04:00
|
|
|
T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(),
|
|
|
|
Name);
|
2008-08-27 20:04:49 +04:00
|
|
|
break;
|
2007-07-11 21:01:13 +04:00
|
|
|
case DeclaratorChunk::Pointer:
|
2009-05-29 19:01:05 +04:00
|
|
|
// Verify that we're not building a pointer to pointer to function with
|
|
|
|
// exception specification.
|
|
|
|
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
|
|
|
|
D.setInvalidType(true);
|
|
|
|
// Build the type anyway.
|
|
|
|
}
|
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-05-29 19:01:05 +04:00
|
|
|
// Verify that we're not building a reference to pointer to function with
|
|
|
|
// exception specification.
|
|
|
|
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
|
|
|
|
D.setInvalidType(true);
|
|
|
|
// Build the type anyway.
|
|
|
|
}
|
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: {
|
2009-05-29 19:01:05 +04:00
|
|
|
// Verify that we're not building an array of pointers to function with
|
|
|
|
// exception specification.
|
|
|
|
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
|
|
|
|
D.setInvalidType(true);
|
|
|
|
// Build the type anyway.
|
|
|
|
}
|
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;
|
2009-05-31 15:47:27 +04: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);
|
|
|
|
}
|
2009-05-28 02:11:52 +04:00
|
|
|
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72555 91177308-0d34-0410-b5e6-96231b3b80d8
2009-05-29 03:31:59 +04:00
|
|
|
if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
|
|
|
|
// C++ [dcl.fct]p6:
|
|
|
|
// Types shall not be defined in return or parameter types.
|
|
|
|
TagDecl *Tag = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
|
|
|
|
if (Tag->isDefinition())
|
|
|
|
Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
|
|
|
|
<< Context.getTypeDeclType(Tag);
|
|
|
|
}
|
|
|
|
|
2009-05-31 15:47:27 +04:00
|
|
|
// Exception specs are not allowed in typedefs. Complain, but add it
|
|
|
|
// anyway.
|
|
|
|
if (FTI.hasExceptionSpec &&
|
|
|
|
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
|
|
|
|
Diag(FTI.getThrowLoc(), diag::err_exception_spec_in_typedef);
|
|
|
|
|
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.
|
2009-05-28 02:11:52 +04:00
|
|
|
llvm::SmallVector<QualType, 4> Exceptions;
|
|
|
|
Exceptions.reserve(FTI.NumExceptions);
|
2009-05-29 22:02:33 +04:00
|
|
|
for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
|
|
|
|
QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
|
|
|
|
// Check that the type is valid for an exception spec, and drop it
|
|
|
|
// if not.
|
|
|
|
if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
|
|
|
|
Exceptions.push_back(ET);
|
|
|
|
}
|
2009-05-28 02:11:52 +04:00
|
|
|
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals,
|
|
|
|
FTI.hasExceptionSpec,
|
|
|
|
FTI.hasAnyExceptionSpec,
|
2009-05-29 22:02:33 +04:00
|
|
|
Exceptions.size(), Exceptions.data());
|
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);
|
|
|
|
}
|
2009-05-28 02:11:52 +04:00
|
|
|
|
|
|
|
llvm::SmallVector<QualType, 4> Exceptions;
|
|
|
|
Exceptions.reserve(FTI.NumExceptions);
|
2009-05-29 22:02:33 +04:00
|
|
|
for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
|
|
|
|
QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
|
|
|
|
// Check that the type is valid for an exception spec, and drop it if
|
|
|
|
// not.
|
|
|
|
if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
|
|
|
|
Exceptions.push_back(ET);
|
|
|
|
}
|
2009-05-28 02:11:52 +04:00
|
|
|
|
2009-05-21 13:52:38 +04:00
|
|
|
T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(),
|
2009-05-28 02:11:52 +04:00
|
|
|
FTI.isVariadic, FTI.TypeQuals,
|
|
|
|
FTI.hasExceptionSpec,
|
|
|
|
FTI.hasAnyExceptionSpec,
|
2009-05-29 22:02:33 +04:00
|
|
|
Exceptions.size(), Exceptions.data());
|
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.
|
|
|
|
QualType ClsType;
|
2009-06-10 02:17:39 +04:00
|
|
|
if (isDependentScopeSpecifier(DeclType.Mem.Scope())) {
|
|
|
|
NestedNameSpecifier *NNS
|
|
|
|
= (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep();
|
|
|
|
assert(NNS->getAsType() && "Nested-name-specifier must name a type");
|
|
|
|
ClsType = QualType(NNS->getAsType(), 0);
|
|
|
|
} else if (CXXRecordDecl *RD
|
|
|
|
= dyn_cast_or_null<CXXRecordDecl>(
|
|
|
|
computeDeclContext(DeclType.Mem.Scope()))) {
|
2009-01-25 00:16:55 +03:00
|
|
|
ClsType = Context.getTagDeclType(RD);
|
|
|
|
} else {
|
2009-06-10 02:17:39 +04:00
|
|
|
Diag(DeclType.Mem.Scope().getBeginLoc(),
|
|
|
|
diag::err_illegal_decl_mempointer_in_nonclass)
|
|
|
|
<< (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
|
|
|
|
<< DeclType.Mem.Scope().getRange();
|
2009-01-25 00:16:55 +03:00
|
|
|
D.setInvalidType(true);
|
|
|
|
}
|
|
|
|
|
2009-06-10 02:17:39 +04:00
|
|
|
if (!ClsType.isNull())
|
|
|
|
T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals,
|
|
|
|
DeclType.Loc, D.getIdentifier());
|
|
|
|
if (T.isNull()) {
|
2009-01-25 00:16:55 +03:00
|
|
|
T = Context.IntTy;
|
2009-06-10 02:17:39 +04:00
|
|
|
D.setInvalidType(true);
|
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;
|
|
|
|
}
|
|
|
|
|
2009-05-29 22:02:33 +04:00
|
|
|
/// CheckSpecifiedExceptionType - Check if the given type is valid in an
|
|
|
|
/// exception specification. Incomplete types, or pointers to incomplete types
|
|
|
|
/// other than void are not allowed.
|
|
|
|
bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
|
|
|
|
// FIXME: This may not correctly work with the fix for core issue 437,
|
|
|
|
// where a class's own type is considered complete within its body.
|
|
|
|
|
|
|
|
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
|
|
|
|
// an incomplete type.
|
|
|
|
if (T->isIncompleteType())
|
|
|
|
return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
|
|
|
|
<< Range << T << /*direct*/0;
|
|
|
|
|
|
|
|
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
|
|
|
|
// an incomplete type a pointer or reference to an incomplete type, other
|
|
|
|
// than (cv) void*.
|
|
|
|
int kind;
|
|
|
|
if (const PointerType* IT = T->getAsPointerType()) {
|
|
|
|
T = IT->getPointeeType();
|
|
|
|
kind = 1;
|
|
|
|
} else if (const ReferenceType* IT = T->getAsReferenceType()) {
|
|
|
|
T = IT->getPointeeType();
|
2009-05-31 15:47:27 +04:00
|
|
|
kind = 2;
|
2009-05-29 22:02:33 +04:00
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (T->isIncompleteType() && !T->isVoidType())
|
|
|
|
return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
|
|
|
|
<< Range << T << /*indirect*/kind;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-05-29 19:01:05 +04:00
|
|
|
/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
|
|
|
|
/// to member to a function with an exception specification. This means that
|
|
|
|
/// it is invalid to add another level of indirection.
|
|
|
|
bool Sema::CheckDistantExceptionSpec(QualType T) {
|
|
|
|
if (const PointerType *PT = T->getAsPointerType())
|
|
|
|
T = PT->getPointeeType();
|
|
|
|
else if (const MemberPointerType *PT = T->getAsMemberPointerType())
|
|
|
|
T = PT->getPointeeType();
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const FunctionProtoType *FnT = T->getAsFunctionProtoType();
|
|
|
|
if (!FnT)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return FnT->hasExceptionSpec();
|
|
|
|
}
|
|
|
|
|
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!");
|
|
|
|
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72555 91177308-0d34-0410-b5e6-96231b3b80d8
2009-05-29 03:31:59 +04:00
|
|
|
TagDecl *OwnedTag = 0;
|
|
|
|
QualType T = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedTag);
|
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
|
|
|
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72555 91177308-0d34-0410-b5e6-96231b3b80d8
2009-05-29 03:31:59 +04:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
// Check that there are no default arguments (C++ only).
|
2008-05-07 08:49:29 +04:00
|
|
|
CheckExtraCXXDefaultArguments(D);
|
|
|
|
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72555 91177308-0d34-0410-b5e6-96231b3b80d8
2009-05-29 03:31:59 +04:00
|
|
|
// C++0x [dcl.type]p3:
|
|
|
|
// A type-specifier-seq shall not define a class or enumeration
|
|
|
|
// unless it appears in the type-id of an alias-declaration
|
|
|
|
// (7.1.3).
|
|
|
|
if (OwnedTag && OwnedTag->isDefinition())
|
|
|
|
Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
|
|
|
|
<< Context.getTypeDeclType(OwnedTag);
|
|
|
|
}
|
|
|
|
|
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-05-22 03:48:18 +04:00
|
|
|
// FIXME: Add this assertion to help us flush out problems with
|
|
|
|
// checking for dependent types and type-dependent expressions.
|
|
|
|
//
|
|
|
|
// assert(!T->isDependentType() &&
|
|
|
|
// "Can't ask whether a dependent type is complete");
|
|
|
|
|
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
|
|
|
}
|
2009-06-30 02:58:55 +04:00
|
|
|
|
|
|
|
QualType Sema::BuildTypeofExprType(Expr *E) {
|
|
|
|
return Context.getTypeOfExprType(E);
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType Sema::BuildDecltypeType(Expr *E) {
|
|
|
|
if (E->getType() == Context.OverloadTy) {
|
|
|
|
Diag(E->getLocStart(),
|
|
|
|
diag::err_cannot_determine_declared_type_of_overloaded_function);
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
return Context.getDecltypeType(E);
|
|
|
|
}
|