From: John McCall Date: Tue, 12 Oct 2010 00:20:44 +0000 (+0000) Subject: Add some infrastructure for dealing with expressions of 'placeholder' type, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2a984cad5ac3fdceeff2bd99daa7b90979313475;p=clang Add some infrastructure for dealing with expressions of 'placeholder' type, i.e. expressions with an internally-convenient type which should not be appearing in generally valid, complete ASTs. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116281 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 64ca7cd4d5..40a36475e0 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -388,9 +388,8 @@ public: CanQualType FloatTy, DoubleTy, LongDoubleTy; CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; CanQualType VoidPtrTy, NullPtrTy; - CanQualType OverloadTy; + CanQualType OverloadTy, UndeducedAutoTy; CanQualType DependentTy; - CanQualType UndeducedAutoTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t, diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index fdd1d165a8..6358ab80aa 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -867,6 +867,12 @@ public: /// isSpecificBuiltinType - Test for a particular builtin type. bool isSpecificBuiltinType(unsigned K) const; + /// isPlaceholderType - Test for a type which does not represent an + /// actual type-system type but is instead used as a placeholder for + /// various convenient purposes within Clang. All such types are + /// BuiltinTypes. + bool isPlaceholderType() const; + /// isIntegerType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) @@ -1105,8 +1111,13 @@ public: NullPtr, // This is the type of C++0x 'nullptr'. + /// This represents the type of an expression whose type is + /// totally unknown, e.g. 'T::foo'. It is permitted for this to + /// appear in situations where the structure of the type is + /// theoretically deducible. + Dependent, + Overload, // This represents the type of an overloaded function declaration. - Dependent, // This represents the type of a type-dependent expression. UndeducedAuto, // In C++0x, this represents the type of an auto variable // that has not been deduced yet. @@ -1156,6 +1167,14 @@ public: return TypeKind >= Float && TypeKind <= LongDouble; } + /// Determines whether this type is a "forbidden" placeholder type, + /// i.e. a type which cannot appear in arbitrary positions in a + /// fully-formed expression. + bool isPlaceholderType() const { + return TypeKind == Overload || + TypeKind == UndeducedAuto; + } + static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } static bool classof(const BuiltinType *) { return true; } }; @@ -3612,6 +3631,12 @@ inline bool Type::isSpecificBuiltinType(unsigned K) const { return false; } +inline bool Type::isPlaceholderType() const { + if (const BuiltinType *BT = getAs()) + return BT->isPlaceholderType(); + return false; +} + /// \brief Determines whether this is a type for which one can define /// an overloaded operator. inline bool Type::isOverloadableType() const { diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 770f837c2f..c06b08dd8b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -800,8 +800,7 @@ def err_temp_copy_incomplete : Error< // C++0x decltype def err_cannot_determine_declared_type_of_overloaded_function : Error< - "cannot determine the %select{type|declared type}0 of an overloaded " - "function">; + "cannot determine the type of an overloaded function">; // C++0x auto def err_auto_variable_cannot_appear_in_own_initializer : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 889585ab0e..7d5fda20ba 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -646,8 +646,8 @@ public: QualType getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T); - QualType BuildTypeofExprType(Expr *E); - QualType BuildDecltypeType(Expr *E); + QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); + QualType BuildDecltypeType(Expr *E, SourceLocation Loc); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. @@ -1758,9 +1758,10 @@ public: ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, void *TyOrEx, const SourceRange &ArgRange); - bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R); + ExprResult CheckPlaceholderExpr(Expr *E, SourceLocation Loc); + bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, - const SourceRange &R, bool isSizeof); + SourceRange R, bool isSizeof); ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e25429bfb9..c7b014efb5 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -329,9 +329,6 @@ void ASTContext::InitBuiltinTypes() { else // C99 Char32Ty = getFromTargetType(Target.getChar32Type()); - // Placeholder type for functions. - InitBuiltinType(OverloadTy, BuiltinType::Overload); - // Placeholder type for type-dependent expressions whose type is // completely unknown. No code should ever check a type against // DependentTy and users should never see it; however, it is here to @@ -339,9 +336,12 @@ void ASTContext::InitBuiltinTypes() { // expressions. InitBuiltinType(DependentTy, BuiltinType::Dependent); + // Placeholder type for functions. + InitBuiltinType(OverloadTy, BuiltinType::Overload); + // Placeholder type for C++0x auto declarations whose real type has // not yet been deduced. - InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto); + InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto); // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 92997ecafd..ef01cced87 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2121,7 +2121,7 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L, /// See C99 6.3.2.1p[2-4] for more details. bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, SourceLocation OpLoc, - const SourceRange &ExprRange, + SourceRange ExprRange, bool isSizeof) { if (exprType->isDependentType()) return false; @@ -2160,17 +2160,11 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, return true; } - if (Context.hasSameUnqualifiedType(exprType, Context.OverloadTy)) { - Diag(OpLoc, diag::err_sizeof_alignof_overloaded_function_type) - << !isSizeof << ExprRange; - return true; - } - return false; } -bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, - const SourceRange &ExprRange) { +static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, + SourceRange ExprRange) { E = E->IgnoreParens(); // alignof decl is always ok. @@ -2182,7 +2176,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, return false; if (E->getBitField()) { - Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange; + S. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange; return true; } @@ -2192,7 +2186,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, if (isa(ME->getMemberDecl())) return false; - return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false); + return S.CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false); } /// \brief Build a sizeof or alignof expression given a type operand. @@ -2220,12 +2214,16 @@ Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo, ExprResult Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { + ExprResult PResult = CheckPlaceholderExpr(E, OpLoc); + if (PResult.isInvalid()) return ExprError(); + E = PResult.take(); + // Verify that the operand is valid. bool isInvalid = false; if (E->isTypeDependent()) { // Delay type-checking for type-dependent expressions. } else if (!isSizeOf) { - isInvalid = CheckAlignOfExpr(E, OpLoc, R); + isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R); } else if (E->getBitField()) { // C99 6.5.3.4p1. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; @@ -8107,3 +8105,35 @@ ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, return Owned(Sub); } + +/// Check for operands with placeholder types and complain if found. +/// Returns true if there was an error and no recovery was possible. +ExprResult Sema::CheckPlaceholderExpr(Expr *E, SourceLocation Loc) { + const BuiltinType *BT = E->getType()->getAs(); + if (!BT || !BT->isPlaceholderType()) return Owned(E); + + // If this is overload, check for a single overload. + if (BT->getKind() == BuiltinType::Overload) { + if (FunctionDecl *Specialization + = ResolveSingleFunctionTemplateSpecialization(E)) { + // The access doesn't really matter in this case. + DeclAccessPair Found = DeclAccessPair::make(Specialization, + Specialization->getAccess()); + E = FixOverloadedFunctionReference(E, Found, Specialization); + if (!E) return ExprError(); + return Owned(E); + } + + Diag(Loc, diag::err_cannot_determine_declared_type_of_overloaded_function) + << E->getSourceRange(); + return ExprError(); + } + + // Otherwise it's a use of undeduced auto. + assert(BT->getKind() == BuiltinType::UndeducedAuto); + + DeclRefExpr *DRE = cast(E->IgnoreParens()); + Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) + << DRE->getDecl() << E->getSourceRange(); + return ExprError(); +} diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 32344559d7..c7dc80e7ce 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -350,7 +350,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = TheSema.BuildTypeofExprType(E); + Result = TheSema.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; TheDeclarator.setInvalidType(true); @@ -361,7 +361,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = TheSema.BuildDecltypeType(E); + Result = TheSema.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; TheDeclarator.setInvalidType(true); @@ -2196,25 +2196,11 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, return Context.getElaboratedType(Keyword, NNS, T); } -QualType Sema::BuildTypeofExprType(Expr *E) { - if (E->getType() == Context.OverloadTy) { - // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a - // function template specialization wherever deduction cannot occur. - if (FunctionDecl *Specialization - = ResolveSingleFunctionTemplateSpecialization(E)) { - // The access doesn't really matter in this case. - DeclAccessPair Found = DeclAccessPair::make(Specialization, - Specialization->getAccess()); - E = FixOverloadedFunctionReference(E, Found, Specialization); - if (!E) - return QualType(); - } else { - Diag(E->getLocStart(), - diag::err_cannot_determine_declared_type_of_overloaded_function) - << false << E->getSourceRange(); - return QualType(); - } - } +QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { + ExprResult ER = CheckPlaceholderExpr(E, Loc); + if (ER.isInvalid()) return QualType(); + E = ER.take(); + if (!E->isTypeDependent()) { QualType T = E->getType(); if (const TagType *TT = T->getAs()) @@ -2223,25 +2209,10 @@ QualType Sema::BuildTypeofExprType(Expr *E) { return Context.getTypeOfExprType(E); } -QualType Sema::BuildDecltypeType(Expr *E) { - if (E->getType() == Context.OverloadTy) { - // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a - // function template specialization wherever deduction cannot occur. - if (FunctionDecl *Specialization - = ResolveSingleFunctionTemplateSpecialization(E)) { - // The access doesn't really matter in this case. - DeclAccessPair Found = DeclAccessPair::make(Specialization, - Specialization->getAccess()); - E = FixOverloadedFunctionReference(E, Found, Specialization); - if (!E) - return QualType(); - } else { - Diag(E->getLocStart(), - diag::err_cannot_determine_declared_type_of_overloaded_function) - << true << E->getSourceRange(); - return QualType(); - } - } +QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { + ExprResult ER = CheckPlaceholderExpr(E, Loc); + if (ER.isInvalid()) return QualType(); + E = ER.take(); return Context.getDecltypeType(E); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 5eac2cbf7c..be8295ea1e 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -495,7 +495,7 @@ public: /// /// By default, performs semantic analysis when building the typeof type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildTypeOfExprType(Expr *Underlying); + QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc); /// \brief Build a new typeof(type) type. /// @@ -506,7 +506,7 @@ public: /// /// By default, performs semantic analysis when building the decltype type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildDecltypeType(Expr *Underlying); + QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc); /// \brief Build a new template specialization type. /// @@ -3065,7 +3065,7 @@ QualType TreeTransform::TransformTypeOfExprType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || E.get() != TL.getUnderlyingExpr()) { - Result = getDerived().RebuildTypeOfExprType(E.get()); + Result = getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc()); if (Result.isNull()) return QualType(); } @@ -3120,7 +3120,7 @@ QualType TreeTransform::TransformDecltypeType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || E.get() != T->getUnderlyingExpr()) { - Result = getDerived().RebuildDecltypeType(E.get()); + Result = getDerived().RebuildDecltypeType(E.get(), TL.getNameLoc()); if (Result.isNull()) return QualType(); } @@ -6502,8 +6502,9 @@ QualType TreeTransform::RebuildUnresolvedUsingType(Decl *D) { } template -QualType TreeTransform::RebuildTypeOfExprType(Expr *E) { - return SemaRef.BuildTypeofExprType(E); +QualType TreeTransform::RebuildTypeOfExprType(Expr *E, + SourceLocation Loc) { + return SemaRef.BuildTypeofExprType(E, Loc); } template @@ -6512,8 +6513,9 @@ QualType TreeTransform::RebuildTypeOfType(QualType Underlying) { } template -QualType TreeTransform::RebuildDecltypeType(Expr *E) { - return SemaRef.BuildDecltypeType(E); +QualType TreeTransform::RebuildDecltypeType(Expr *E, + SourceLocation Loc) { + return SemaRef.BuildDecltypeType(E, Loc); } template diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp index dd64d6a23a..945129c26a 100644 --- a/test/SemaCXX/alignof-sizeof-reference.cpp +++ b/test/SemaCXX/alignof-sizeof-reference.cpp @@ -11,5 +11,5 @@ void test() { void f(); void f(int); void g() { - sizeof(&f); // expected-error{{invalid application of 'sizeof' to an overloaded function}} + sizeof(&f); // expected-error{{cannot determine the type of an overloaded function}} } diff --git a/test/SemaCXX/decltype-overloaded-functions.cpp b/test/SemaCXX/decltype-overloaded-functions.cpp index 0aa49b0cec..f1b29b0864 100644 --- a/test/SemaCXX/decltype-overloaded-functions.cpp +++ b/test/SemaCXX/decltype-overloaded-functions.cpp @@ -2,10 +2,10 @@ void f(); void f(int); -decltype(f) a; // expected-error{{cannot determine the declared type of an overloaded function}} +decltype(f) a; // expected-error{{cannot determine the type of an overloaded function}} template struct S { - decltype(T::f) * f; // expected-error{{cannot determine the declared type of an overloaded function}} + decltype(T::f) * f; // expected-error{{cannot determine the type of an overloaded function}} }; struct K { void f(); void f(int); };